home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / game / shoot / WarpQuake_src.lha / WarpQuakeSrc / menu.c < prev    next >
C/C++ Source or Header  |  2000-03-02  |  67KB  |  3,232 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "quakedef.h"
  21.  
  22. #ifdef _WIN32
  23. #include "winquake.h"
  24. #endif
  25.  
  26. void (*vid_menudrawfn)(void);
  27. void (*vid_menukeyfn)(int key);
  28.  
  29. enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state;
  30.  
  31. void M_Menu_Main_f (void);
  32.     void M_Menu_SinglePlayer_f (void);
  33.         void M_Menu_Load_f (void);
  34.         void M_Menu_Save_f (void);
  35.     void M_Menu_MultiPlayer_f (void);
  36.         void M_Menu_Setup_f (void);
  37.         void M_Menu_Net_f (void);
  38.     void M_Menu_Options_f (void);
  39.         void M_Menu_Keys_f (void);
  40.         void M_Menu_Video_f (void);
  41.     void M_Menu_Help_f (void);
  42.     void M_Menu_Quit_f (void);
  43. void M_Menu_SerialConfig_f (void);
  44.     void M_Menu_ModemConfig_f (void);
  45. void M_Menu_LanConfig_f (void);
  46. void M_Menu_GameOptions_f (void);
  47. void M_Menu_Search_f (void);
  48. void M_Menu_ServerList_f (void);
  49.  
  50. void M_Main_Draw (void);
  51.     void M_SinglePlayer_Draw (void);
  52.         void M_Load_Draw (void);
  53.         void M_Save_Draw (void);
  54.     void M_MultiPlayer_Draw (void);
  55.         void M_Setup_Draw (void);
  56.         void M_Net_Draw (void);
  57.     void M_Options_Draw (void);
  58.         void M_Keys_Draw (void);
  59.         void M_Video_Draw (void);
  60.     void M_Help_Draw (void);
  61.     void M_Quit_Draw (void);
  62. void M_SerialConfig_Draw (void);
  63.     void M_ModemConfig_Draw (void);
  64. void M_LanConfig_Draw (void);
  65. void M_GameOptions_Draw (void);
  66. void M_Search_Draw (void);
  67. void M_ServerList_Draw (void);
  68.  
  69. void M_Main_Key (int key);
  70.     void M_SinglePlayer_Key (int key);
  71.         void M_Load_Key (int key);
  72.         void M_Save_Key (int key);
  73.     void M_MultiPlayer_Key (int key);
  74.         void M_Setup_Key (int key);
  75.         void M_Net_Key (int key);
  76.     void M_Options_Key (int key);
  77.         void M_Keys_Key (int key);
  78.         void M_Video_Key (int key);
  79.     void M_Help_Key (int key);
  80.     void M_Quit_Key (int key);
  81. void M_SerialConfig_Key (int key);
  82.     void M_ModemConfig_Key (int key);
  83. void M_LanConfig_Key (int key);
  84. void M_GameOptions_Key (int key);
  85. void M_Search_Key (int key);
  86. void M_ServerList_Key (int key);
  87.  
  88. qboolean    m_entersound;        // play after drawing a frame, so caching
  89.                                 // won't disrupt the sound
  90. qboolean    m_recursiveDraw;
  91.  
  92. int            m_return_state;
  93. qboolean    m_return_onerror;
  94. char        m_return_reason [32];
  95.  
  96. #define StartingGame    (m_multiplayer_cursor == 1)
  97. #define JoiningGame        (m_multiplayer_cursor == 0)
  98. #define SerialConfig    (m_net_cursor == 0)
  99. #define DirectConfig    (m_net_cursor == 1)
  100. #define    IPXConfig        (m_net_cursor == 2)
  101. #define    TCPIPConfig        (m_net_cursor == 3)
  102.  
  103. void M_ConfigureNetSubsystem(void);
  104.  
  105. /*
  106. ================
  107. M_DrawCharacter
  108.  
  109. Draws one solid graphics character
  110. ================
  111. */
  112. void M_DrawCharacter (int cx, int line, int num)
  113. {
  114.     Draw_Character ( cx + ((vid.width - 320)>>1), line, num);
  115. }
  116.  
  117. void M_Print (int cx, int cy, char *str)
  118. {
  119.     while (*str)
  120.     {
  121.         M_DrawCharacter (cx, cy, (*str)+128);
  122.         str++;
  123.         cx += 8;
  124.     }
  125. }
  126.  
  127. void M_PrintWhite (int cx, int cy, char *str)
  128. {
  129.     while (*str)
  130.     {
  131.         M_DrawCharacter (cx, cy, *str);
  132.         str++;
  133.         cx += 8;
  134.     }
  135. }
  136.  
  137. void M_DrawTransPic (int x, int y, qpic_t *pic)
  138. {
  139.     Draw_TransPic (x + ((vid.width - 320)>>1), y, pic);
  140. }
  141.  
  142. void M_DrawPic (int x, int y, qpic_t *pic)
  143. {
  144.     Draw_Pic (x + ((vid.width - 320)>>1), y, pic);
  145. }
  146.  
  147. byte identityTable[256];
  148. byte translationTable[256];
  149.  
  150. void M_BuildTranslationTable(int top, int bottom)
  151. {
  152.     int        j;
  153.     byte    *dest, *source;
  154.  
  155.     for (j = 0; j < 256; j++)
  156.         identityTable[j] = j;
  157.     dest = translationTable;
  158.     source = identityTable;
  159.     memcpy (dest, source, 256);
  160.  
  161.     if (top < 128)    // the artists made some backwards ranges.  sigh.
  162.         memcpy (dest + TOP_RANGE, source + top, 16);
  163.     else
  164.         for (j=0 ; j<16 ; j++)
  165.             dest[TOP_RANGE+j] = source[top+15-j];
  166.  
  167.     if (bottom < 128)
  168.         memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
  169.     else
  170.         for (j=0 ; j<16 ; j++)
  171.             dest[BOTTOM_RANGE+j] = source[bottom+15-j];
  172. }
  173.  
  174.  
  175. void M_DrawTransPicTranslate (int x, int y, qpic_t *pic)
  176. {
  177.     Draw_TransPicTranslate (x + ((vid.width - 320)>>1), y, pic, translationTable);
  178. }
  179.  
  180.  
  181. void M_DrawTextBox (int x, int y, int width, int lines)
  182. {
  183.     qpic_t    *p;
  184.     int        cx, cy;
  185.     int        n;
  186.  
  187.     // draw left side
  188.     cx = x;
  189.     cy = y;
  190.     p = Draw_CachePic ("gfx/box_tl.lmp");
  191.     M_DrawTransPic (cx, cy, p);
  192.     p = Draw_CachePic ("gfx/box_ml.lmp");
  193.     for (n = 0; n < lines; n++)
  194.     {
  195.         cy += 8;
  196.         M_DrawTransPic (cx, cy, p);
  197.     }
  198.     p = Draw_CachePic ("gfx/box_bl.lmp");
  199.     M_DrawTransPic (cx, cy+8, p);
  200.  
  201.     // draw middle
  202.     cx += 8;
  203.     while (width > 0)
  204.     {
  205.         cy = y;
  206.         p = Draw_CachePic ("gfx/box_tm.lmp");
  207.         M_DrawTransPic (cx, cy, p);
  208.         p = Draw_CachePic ("gfx/box_mm.lmp");
  209.         for (n = 0; n < lines; n++)
  210.         {
  211.             cy += 8;
  212.             if (n == 1)
  213.                 p = Draw_CachePic ("gfx/box_mm2.lmp");
  214.             M_DrawTransPic (cx, cy, p);
  215.         }
  216.         p = Draw_CachePic ("gfx/box_bm.lmp");
  217.         M_DrawTransPic (cx, cy+8, p);
  218.         width -= 2;
  219.         cx += 16;
  220.     }
  221.  
  222.     // draw right side
  223.     cy = y;
  224.     p = Draw_CachePic ("gfx/box_tr.lmp");
  225.     M_DrawTransPic (cx, cy, p);
  226.     p = Draw_CachePic ("gfx/box_mr.lmp");
  227.     for (n = 0; n < lines; n++)
  228.     {
  229.         cy += 8;
  230.         M_DrawTransPic (cx, cy, p);
  231.     }
  232.     p = Draw_CachePic ("gfx/box_br.lmp");
  233.     M_DrawTransPic (cx, cy+8, p);
  234. }
  235.  
  236. //=============================================================================
  237.  
  238. int m_save_demonum;
  239.  
  240. /*
  241. ================
  242. M_ToggleMenu_f
  243. ================
  244. */
  245. void M_ToggleMenu_f (void)
  246. {
  247.     m_entersound = true;
  248.  
  249.     if (key_dest == key_menu)
  250.     {
  251.         if (m_state != m_main)
  252.         {
  253.             M_Menu_Main_f ();
  254.             return;
  255.         }
  256.         key_dest = key_game;
  257.         m_state = m_none;
  258.         return;
  259.     }
  260.     if (key_dest == key_console)
  261.     {
  262.         Con_ToggleConsole_f ();
  263.     }
  264.     else
  265.     {
  266.         M_Menu_Main_f ();
  267.     }
  268. }
  269.  
  270.  
  271. //=============================================================================
  272. /* MAIN MENU */
  273.  
  274. int    m_main_cursor;
  275. #define    MAIN_ITEMS    5
  276.  
  277.  
  278. void M_Menu_Main_f (void)
  279. {
  280.     if (key_dest != key_menu)
  281.     {
  282.         m_save_demonum = cls.demonum;
  283.         cls.demonum = -1;
  284.     }
  285.     key_dest = key_menu;
  286.     m_state = m_main;
  287.     m_entersound = true;
  288. }
  289.  
  290.  
  291. void M_Main_Draw (void)
  292. {
  293.     int        f;
  294.     qpic_t    *p;
  295.  
  296.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  297.     p = Draw_CachePic ("gfx/ttl_main.lmp");
  298.     M_DrawPic ( (320-p->width)/2, 4, p);
  299.     M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") );
  300.  
  301.     f = (int)(host_time * 10)%6;
  302.  
  303.     M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  304. }
  305.  
  306.  
  307. void M_Main_Key (int key)
  308. {
  309.     switch (key)
  310.     {
  311.     case K_ESCAPE:
  312.         key_dest = key_game;
  313.         m_state = m_none;
  314.         cls.demonum = m_save_demonum;
  315.         if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)
  316.             CL_NextDemo ();
  317.         break;
  318.  
  319.     case K_DOWNARROW:
  320.         S_LocalSound ("misc/menu1.wav");
  321.         if (++m_main_cursor >= MAIN_ITEMS)
  322.             m_main_cursor = 0;
  323.         break;
  324.  
  325.     case K_UPARROW:
  326.         S_LocalSound ("misc/menu1.wav");
  327.         if (--m_main_cursor < 0)
  328.             m_main_cursor = MAIN_ITEMS - 1;
  329.         break;
  330.  
  331.     case K_ENTER:
  332.         m_entersound = true;
  333.  
  334.         switch (m_main_cursor)
  335.         {
  336.         case 0:
  337.             M_Menu_SinglePlayer_f ();
  338.             break;
  339.  
  340.         case 1:
  341.             M_Menu_MultiPlayer_f ();
  342.             break;
  343.  
  344.         case 2:
  345.             M_Menu_Options_f ();
  346.             break;
  347.  
  348.         case 3:
  349.             M_Menu_Help_f ();
  350.             break;
  351.  
  352.         case 4:
  353.             M_Menu_Quit_f ();
  354.             break;
  355.         }
  356.     }
  357. }
  358.  
  359. //=============================================================================
  360. /* SINGLE PLAYER MENU */
  361.  
  362. int    m_singleplayer_cursor;
  363. #define    SINGLEPLAYER_ITEMS    3
  364.  
  365.  
  366. void M_Menu_SinglePlayer_f (void)
  367. {
  368.     key_dest = key_menu;
  369.     m_state = m_singleplayer;
  370.     m_entersound = true;
  371. }
  372.  
  373.  
  374. void M_SinglePlayer_Draw (void)
  375. {
  376.     int        f;
  377.     qpic_t    *p;
  378.  
  379.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  380.     p = Draw_CachePic ("gfx/ttl_sgl.lmp");
  381.     M_DrawPic ( (320-p->width)/2, 4, p);
  382.     M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") );
  383.  
  384.     f = (int)(host_time * 10)%6;
  385.  
  386.     M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  387. }
  388.  
  389.  
  390. void M_SinglePlayer_Key (int key)
  391. {
  392.     switch (key)
  393.     {
  394.     case K_ESCAPE:
  395.         M_Menu_Main_f ();
  396.         break;
  397.  
  398.     case K_DOWNARROW:
  399.         S_LocalSound ("misc/menu1.wav");
  400.         if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
  401.             m_singleplayer_cursor = 0;
  402.         break;
  403.  
  404.     case K_UPARROW:
  405.         S_LocalSound ("misc/menu1.wav");
  406.         if (--m_singleplayer_cursor < 0)
  407.             m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
  408.         break;
  409.  
  410.     case K_ENTER:
  411.         m_entersound = true;
  412.  
  413.         switch (m_singleplayer_cursor)
  414.         {
  415.         case 0:
  416.             if (sv.active)
  417.                 if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n"))
  418.                     break;
  419.             key_dest = key_game;
  420.             if (sv.active)
  421.                 Cbuf_AddText ("disconnect\n");
  422.             Cbuf_AddText ("maxplayers 1\n");
  423.             Cbuf_AddText ("map start\n");
  424.             break;
  425.  
  426.         case 1:
  427.             M_Menu_Load_f ();
  428.             break;
  429.  
  430.         case 2:
  431.             M_Menu_Save_f ();
  432.             break;
  433.         }
  434.     }
  435. }
  436.  
  437. //=============================================================================
  438. /* LOAD/SAVE MENU */
  439.  
  440. int        load_cursor;        // 0 < load_cursor < MAX_SAVEGAMES
  441.  
  442. #define    MAX_SAVEGAMES        12
  443. char    m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];
  444. int        loadable[MAX_SAVEGAMES];
  445.  
  446. void M_ScanSaves (void)
  447. {
  448.     int        i, j;
  449.     char    name[MAX_OSPATH];
  450.     FILE    *f;
  451.     int        version;
  452.  
  453.     for (i=0 ; i<MAX_SAVEGAMES ; i++)
  454.     {
  455.         strcpy (m_filenames[i], "--- UNUSED SLOT ---");
  456.         loadable[i] = false;
  457.         sprintf (name, "%s/s%i.sav", com_gamedir, i);
  458.         f = fopen (name, "r");
  459.         if (!f)
  460.             continue;
  461.         fscanf (f, "%i\n", &version);
  462.         fscanf (f, "%79s\n", name);
  463.         strncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);
  464.  
  465.     // change _ back to space
  466.         for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
  467.             if (m_filenames[i][j] == '_')
  468.                 m_filenames[i][j] = ' ';
  469.         loadable[i] = true;
  470.         fclose (f);
  471.     }
  472. }
  473.  
  474. void M_Menu_Load_f (void)
  475. {
  476.     m_entersound = true;
  477.     m_state = m_load;
  478.     key_dest = key_menu;
  479.     M_ScanSaves ();
  480. }
  481.  
  482.  
  483. void M_Menu_Save_f (void)
  484. {
  485.     if (!sv.active)
  486.         return;
  487.     if (cl.intermission)
  488.         return;
  489.     if (svs.maxclients != 1)
  490.         return;
  491.     m_entersound = true;
  492.     m_state = m_save;
  493.     key_dest = key_menu;
  494.     M_ScanSaves ();
  495. }
  496.  
  497.  
  498. void M_Load_Draw (void)
  499. {
  500.     int        i;
  501.     qpic_t    *p;
  502.  
  503.     p = Draw_CachePic ("gfx/p_load.lmp");
  504.     M_DrawPic ( (320-p->width)/2, 4, p);
  505.  
  506.     for (i=0 ; i< MAX_SAVEGAMES; i++)
  507.         M_Print (16, 32 + 8*i, m_filenames[i]);
  508.  
  509. // line cursor
  510.     M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
  511. }
  512.  
  513.  
  514. void M_Save_Draw (void)
  515. {
  516.     int        i;
  517.     qpic_t    *p;
  518.  
  519.     p = Draw_CachePic ("gfx/p_save.lmp");
  520.     M_DrawPic ( (320-p->width)/2, 4, p);
  521.  
  522.     for (i=0 ; i<MAX_SAVEGAMES ; i++)
  523.         M_Print (16, 32 + 8*i, m_filenames[i]);
  524.  
  525. // line cursor
  526.     M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));
  527. }
  528.  
  529.  
  530. void M_Load_Key (int k)
  531. {
  532.     switch (k)
  533.     {
  534.     case K_ESCAPE:
  535.         M_Menu_SinglePlayer_f ();
  536.         break;
  537.  
  538.     case K_ENTER:
  539.         S_LocalSound ("misc/menu2.wav");
  540.         if (!loadable[load_cursor])
  541.             return;
  542.         m_state = m_none;
  543.         key_dest = key_game;
  544.  
  545.     // Host_Loadgame_f can't bring up the loading plaque because too much
  546.     // stack space has been used, so do it now
  547.         SCR_BeginLoadingPlaque ();
  548.  
  549.     // issue the load command
  550.         Cbuf_AddText (va ("load s%i\n", load_cursor) );
  551.         return;
  552.  
  553.     case K_UPARROW:
  554.     case K_LEFTARROW:
  555.         S_LocalSound ("misc/menu1.wav");
  556.         load_cursor--;
  557.         if (load_cursor < 0)
  558.             load_cursor = MAX_SAVEGAMES-1;
  559.         break;
  560.  
  561.     case K_DOWNARROW:
  562.     case K_RIGHTARROW:
  563.         S_LocalSound ("misc/menu1.wav");
  564.         load_cursor++;
  565.         if (load_cursor >= MAX_SAVEGAMES)
  566.             load_cursor = 0;
  567.         break;
  568.     }
  569. }
  570.  
  571.  
  572. void M_Save_Key (int k)
  573. {
  574.     switch (k)
  575.     {
  576.     case K_ESCAPE:
  577.         M_Menu_SinglePlayer_f ();
  578.         break;
  579.  
  580.     case K_ENTER:
  581.         m_state = m_none;
  582.         key_dest = key_game;
  583.         Cbuf_AddText (va("save s%i\n", load_cursor));
  584.         return;
  585.  
  586.     case K_UPARROW:
  587.     case K_LEFTARROW:
  588.         S_LocalSound ("misc/menu1.wav");
  589.         load_cursor--;
  590.         if (load_cursor < 0)
  591.             load_cursor = MAX_SAVEGAMES-1;
  592.         break;
  593.  
  594.     case K_DOWNARROW:
  595.     case K_RIGHTARROW:
  596.         S_LocalSound ("misc/menu1.wav");
  597.         load_cursor++;
  598.         if (load_cursor >= MAX_SAVEGAMES)
  599.             load_cursor = 0;
  600.         break;
  601.     }
  602. }
  603.  
  604. //=============================================================================
  605. /* MULTIPLAYER MENU */
  606.  
  607. int    m_multiplayer_cursor;
  608. #define    MULTIPLAYER_ITEMS    3
  609.  
  610.  
  611. void M_Menu_MultiPlayer_f (void)
  612. {
  613.     key_dest = key_menu;
  614.     m_state = m_multiplayer;
  615.     m_entersound = true;
  616. }
  617.  
  618.  
  619. void M_MultiPlayer_Draw (void)
  620. {
  621.     int        f;
  622.     qpic_t    *p;
  623.  
  624.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  625.     p = Draw_CachePic ("gfx/p_multi.lmp");
  626.     M_DrawPic ( (320-p->width)/2, 4, p);
  627.     M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") );
  628.  
  629.     f = (int)(host_time * 10)%6;
  630.  
  631.     M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  632.  
  633.     if (serialAvailable || ipxAvailable || tcpipAvailable)
  634.         return;
  635.     M_PrintWhite ((320/2) - ((27*8)/2), 148, "No Communications Available");
  636. }
  637.  
  638.  
  639. void M_MultiPlayer_Key (int key)
  640. {
  641.     switch (key)
  642.     {
  643.     case K_ESCAPE:
  644.         M_Menu_Main_f ();
  645.         break;
  646.  
  647.     case K_DOWNARROW:
  648.         S_LocalSound ("misc/menu1.wav");
  649.         if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
  650.             m_multiplayer_cursor = 0;
  651.         break;
  652.  
  653.     case K_UPARROW:
  654.         S_LocalSound ("misc/menu1.wav");
  655.         if (--m_multiplayer_cursor < 0)
  656.             m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
  657.         break;
  658.  
  659.     case K_ENTER:
  660.         m_entersound = true;
  661.         switch (m_multiplayer_cursor)
  662.         {
  663.         case 0:
  664.             if (serialAvailable || ipxAvailable || tcpipAvailable)
  665.                 M_Menu_Net_f ();
  666.             break;
  667.  
  668.         case 1:
  669.             if (serialAvailable || ipxAvailable || tcpipAvailable)
  670.                 M_Menu_Net_f ();
  671.             break;
  672.  
  673.         case 2:
  674.             M_Menu_Setup_f ();
  675.             break;
  676.         }
  677.     }
  678. }
  679.  
  680. //=============================================================================
  681. /* SETUP MENU */
  682.  
  683. int        setup_cursor = 4;
  684. int        setup_cursor_table[] = {40, 56, 80, 104, 140};
  685.  
  686. char    setup_hostname[16];
  687. char    setup_myname[16];
  688. int        setup_oldtop;
  689. int        setup_oldbottom;
  690. int        setup_top;
  691. int        setup_bottom;
  692.  
  693. #define    NUM_SETUP_CMDS    5
  694.  
  695. void M_Menu_Setup_f (void)
  696. {
  697.     key_dest = key_menu;
  698.     m_state = m_setup;
  699.     m_entersound = true;
  700.     Q_strcpy(setup_myname, cl_name.string);
  701.     Q_strcpy(setup_hostname, hostname.string);
  702.     setup_top = setup_oldtop = ((int)cl_color.value) >> 4;
  703.     setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;
  704. }
  705.  
  706.  
  707. void M_Setup_Draw (void)
  708. {
  709.     qpic_t    *p;
  710.  
  711.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  712.     p = Draw_CachePic ("gfx/p_multi.lmp");
  713.     M_DrawPic ( (320-p->width)/2, 4, p);
  714.  
  715.     M_Print (64, 40, "Hostname");
  716.     M_DrawTextBox (160, 32, 16, 1);
  717.     M_Print (168, 40, setup_hostname);
  718.  
  719.     M_Print (64, 56, "Your name");
  720.     M_DrawTextBox (160, 48, 16, 1);
  721.     M_Print (168, 56, setup_myname);
  722.  
  723.     M_Print (64, 80, "Shirt color");
  724.     M_Print (64, 104, "Pants color");
  725.  
  726.     M_DrawTextBox (64, 140-8, 14, 1);
  727.     M_Print (72, 140, "Accept Changes");
  728.  
  729.     p = Draw_CachePic ("gfx/bigbox.lmp");
  730.     M_DrawTransPic (160, 64, p);
  731.     p = Draw_CachePic ("gfx/menuplyr.lmp");
  732.     M_BuildTranslationTable(setup_top*16, setup_bottom*16);
  733.     M_DrawTransPicTranslate (172, 72, p);
  734.  
  735.     M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));
  736.  
  737.     if (setup_cursor == 0)
  738.         M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
  739.  
  740.     if (setup_cursor == 1)
  741.         M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));
  742. }
  743.  
  744.  
  745. void M_Setup_Key (int k)
  746. {
  747.     int            l;
  748.  
  749.     switch (k)
  750.     {
  751.     case K_ESCAPE:
  752.         M_Menu_MultiPlayer_f ();
  753.         break;
  754.  
  755.     case K_UPARROW:
  756.         S_LocalSound ("misc/menu1.wav");
  757.         setup_cursor--;
  758.         if (setup_cursor < 0)
  759.             setup_cursor = NUM_SETUP_CMDS-1;
  760.         break;
  761.  
  762.     case K_DOWNARROW:
  763.         S_LocalSound ("misc/menu1.wav");
  764.         setup_cursor++;
  765.         if (setup_cursor >= NUM_SETUP_CMDS)
  766.             setup_cursor = 0;
  767.         break;
  768.  
  769.     case K_LEFTARROW:
  770.         if (setup_cursor < 2)
  771.             return;
  772.         S_LocalSound ("misc/menu3.wav");
  773.         if (setup_cursor == 2)
  774.             setup_top = setup_top - 1;
  775.         if (setup_cursor == 3)
  776.             setup_bottom = setup_bottom - 1;
  777.         break;
  778.     case K_RIGHTARROW:
  779.         if (setup_cursor < 2)
  780.             return;
  781. forward:
  782.         S_LocalSound ("misc/menu3.wav");
  783.         if (setup_cursor == 2)
  784.             setup_top = setup_top + 1;
  785.         if (setup_cursor == 3)
  786.             setup_bottom = setup_bottom + 1;
  787.         break;
  788.  
  789.     case K_ENTER:
  790.         if (setup_cursor == 0 || setup_cursor == 1)
  791.             return;
  792.  
  793.         if (setup_cursor == 2 || setup_cursor == 3)
  794.             goto forward;
  795.  
  796.         // setup_cursor == 4 (OK)
  797.         if (Q_strcmp(cl_name.string, setup_myname) != 0)
  798.             Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
  799.         if (Q_strcmp(hostname.string, setup_hostname) != 0)
  800.             Cvar_Set("hostname", setup_hostname);
  801.         if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
  802.             Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
  803.         m_entersound = true;
  804.         M_Menu_MultiPlayer_f ();
  805.         break;
  806.  
  807.     case K_BACKSPACE:
  808.         if (setup_cursor == 0)
  809.         {
  810.             if (strlen(setup_hostname))
  811.                 setup_hostname[strlen(setup_hostname)-1] = 0;
  812.         }
  813.  
  814.         if (setup_cursor == 1)
  815.         {
  816.             if (strlen(setup_myname))
  817.                 setup_myname[strlen(setup_myname)-1] = 0;
  818.         }
  819.         break;
  820.  
  821.     default:
  822.         if (k < 32 || k > 127)
  823.             break;
  824.         if (setup_cursor == 0)
  825.         {
  826.             l = strlen(setup_hostname);
  827.             if (l < 15)
  828.             {
  829.                 setup_hostname[l+1] = 0;
  830.                 setup_hostname[l] = k;
  831.             }
  832.         }
  833.         if (setup_cursor == 1)
  834.         {
  835.             l = strlen(setup_myname);
  836.             if (l < 15)
  837.             {
  838.                 setup_myname[l+1] = 0;
  839.                 setup_myname[l] = k;
  840.             }
  841.         }
  842.     }
  843.  
  844.     if (setup_top > 13)
  845.         setup_top = 0;
  846.     if (setup_top < 0)
  847.         setup_top = 13;
  848.     if (setup_bottom > 13)
  849.         setup_bottom = 0;
  850.     if (setup_bottom < 0)
  851.         setup_bottom = 13;
  852. }
  853.  
  854. //=============================================================================
  855. /* NET MENU */
  856.  
  857. int    m_net_cursor;
  858. int m_net_items;
  859. int m_net_saveHeight;
  860.  
  861. char *net_helpMessage [] =
  862. {
  863. /* .........1.........2.... */
  864.   "                        ",
  865.   " Two computers connected",
  866.   "   through two modems.  ",
  867.   "                        ",
  868.  
  869.   "                        ",
  870.   " Two computers connected",
  871.   " by a null-modem cable. ",
  872.   "                        ",
  873.  
  874.   " Novell network LANs    ",
  875.   " or Windows 95 DOS-box. ",
  876.   "                        ",
  877.   "(LAN=Local Area Network)",
  878.  
  879.   " Commonly used to play  ",
  880.   " over the Internet, but ",
  881.   " also used on a Local   ",
  882.   " Area Network.          "
  883. };
  884.  
  885. void M_Menu_Net_f (void)
  886. {
  887.     key_dest = key_menu;
  888.     m_state = m_net;
  889.     m_entersound = true;
  890.     m_net_items = 4;
  891.  
  892.     if (m_net_cursor >= m_net_items)
  893.         m_net_cursor = 0;
  894.     m_net_cursor--;
  895.     M_Net_Key (K_DOWNARROW);
  896. }
  897.  
  898.  
  899. void M_Net_Draw (void)
  900. {
  901.     int        f;
  902.     qpic_t    *p;
  903.  
  904.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  905.     p = Draw_CachePic ("gfx/p_multi.lmp");
  906.     M_DrawPic ( (320-p->width)/2, 4, p);
  907.  
  908.     f = 32;
  909.  
  910.     if (serialAvailable)
  911.     {
  912.         p = Draw_CachePic ("gfx/netmen1.lmp");
  913.     }
  914.     else
  915.     {
  916. #ifdef _WIN32
  917.         p = NULL;
  918. #else
  919.         p = Draw_CachePic ("gfx/dim_modm.lmp");
  920. #endif
  921.     }
  922.  
  923.     if (p)
  924.         M_DrawTransPic (72, f, p);
  925.  
  926.     f += 19;
  927.  
  928.     if (serialAvailable)
  929.     {
  930.         p = Draw_CachePic ("gfx/netmen2.lmp");
  931.     }
  932.     else
  933.     {
  934. #ifdef _WIN32
  935.         p = NULL;
  936. #else
  937.         p = Draw_CachePic ("gfx/dim_drct.lmp");
  938. #endif
  939.     }
  940.  
  941.     if (p)
  942.         M_DrawTransPic (72, f, p);
  943.  
  944.     f += 19;
  945.     if (ipxAvailable)
  946.         p = Draw_CachePic ("gfx/netmen3.lmp");
  947.     else
  948.         p = Draw_CachePic ("gfx/dim_ipx.lmp");
  949.     M_DrawTransPic (72, f, p);
  950.  
  951.     f += 19;
  952.     if (tcpipAvailable)
  953.         p = Draw_CachePic ("gfx/netmen4.lmp");
  954.     else
  955.         p = Draw_CachePic ("gfx/dim_tcp.lmp");
  956.     M_DrawTransPic (72, f, p);
  957.  
  958.     if (m_net_items == 5)    // JDC, could just be removed
  959.     {
  960.         f += 19;
  961.         p = Draw_CachePic ("gfx/netmen5.lmp");
  962.         M_DrawTransPic (72, f, p);
  963.     }
  964.  
  965.     f = (320-26*8)/2;
  966.     M_DrawTextBox (f, 134, 24, 4);
  967.     f += 8;
  968.     M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]);
  969.     M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]);
  970.     M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]);
  971.     M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]);
  972.  
  973.     f = (int)(host_time * 10)%6;
  974.     M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) );
  975. }
  976.  
  977.  
  978. void M_Net_Key (int k)
  979. {
  980. again:
  981.     switch (k)
  982.     {
  983.     case K_ESCAPE:
  984.         M_Menu_MultiPlayer_f ();
  985.         break;
  986.  
  987.     case K_DOWNARROW:
  988.         S_LocalSound ("misc/menu1.wav");
  989.         if (++m_net_cursor >= m_net_items)
  990.             m_net_cursor = 0;
  991.         break;
  992.  
  993.     case K_UPARROW:
  994.         S_LocalSound ("misc/menu1.wav");
  995.         if (--m_net_cursor < 0)
  996.             m_net_cursor = m_net_items - 1;
  997.         break;
  998.  
  999.     case K_ENTER:
  1000.         m_entersound = true;
  1001.  
  1002.         switch (m_net_cursor)
  1003.         {
  1004.         case 0:
  1005.             M_Menu_SerialConfig_f ();
  1006.             break;
  1007.  
  1008.         case 1:
  1009.             M_Menu_SerialConfig_f ();
  1010.             break;
  1011.  
  1012.         case 2:
  1013.             M_Menu_LanConfig_f ();
  1014.             break;
  1015.  
  1016.         case 3:
  1017.             M_Menu_LanConfig_f ();
  1018.             break;
  1019.  
  1020.         case 4:
  1021. // multiprotocol
  1022.             break;
  1023.         }
  1024.     }
  1025.  
  1026.     if (m_net_cursor == 0 && !serialAvailable)
  1027.         goto again;
  1028.     if (m_net_cursor == 1 && !serialAvailable)
  1029.         goto again;
  1030.     if (m_net_cursor == 2 && !ipxAvailable)
  1031.         goto again;
  1032.     if (m_net_cursor == 3 && !tcpipAvailable)
  1033.         goto again;
  1034. }
  1035.  
  1036. //=============================================================================
  1037. /* OPTIONS MENU */
  1038.  
  1039. #ifdef _WIN32
  1040. #define    OPTIONS_ITEMS    14
  1041. #else
  1042. #define    OPTIONS_ITEMS    13
  1043. #endif
  1044.  
  1045. #define    SLIDER_RANGE    10
  1046.  
  1047. int        options_cursor;
  1048.  
  1049. void M_Menu_Options_f (void)
  1050. {
  1051.     key_dest = key_menu;
  1052.     m_state = m_options;
  1053.     m_entersound = true;
  1054.  
  1055. #ifdef _WIN32
  1056.     if ((options_cursor == 13) && (modestate != MS_WINDOWED))
  1057.     {
  1058.         options_cursor = 0;
  1059.     }
  1060. #endif
  1061. }
  1062.  
  1063.  
  1064. void M_AdjustSliders (int dir)
  1065. {
  1066.     S_LocalSound ("misc/menu3.wav");
  1067.  
  1068.     switch (options_cursor)
  1069.     {
  1070.     case 3:    // screen size
  1071.         scr_viewsize.value += dir * 10;
  1072.         if (scr_viewsize.value < 30)
  1073.             scr_viewsize.value = 30;
  1074.         if (scr_viewsize.value > 120)
  1075.             scr_viewsize.value = 120;
  1076.         Cvar_SetValue ("viewsize", scr_viewsize.value);
  1077.         break;
  1078.     case 4:    // gamma
  1079.         v_gamma.value -= dir * 0.05;
  1080.         if (v_gamma.value < 0.5)
  1081.             v_gamma.value = 0.5;
  1082.         if (v_gamma.value > 1)
  1083.             v_gamma.value = 1;
  1084.         Cvar_SetValue ("gamma", v_gamma.value);
  1085.         break;
  1086.     case 5:    // mouse speed
  1087.         sensitivity.value += dir * 0.5;
  1088.         if (sensitivity.value < 1)
  1089.             sensitivity.value = 1;
  1090.         if (sensitivity.value > 11)
  1091.             sensitivity.value = 11;
  1092.         Cvar_SetValue ("sensitivity", sensitivity.value);
  1093.         break;
  1094.     case 6:    // music volume
  1095. #ifdef _WIN32
  1096.         bgmvolume.value += dir * 1.0;
  1097. #else
  1098.         bgmvolume.value += dir * 0.1;
  1099. #endif
  1100.         if (bgmvolume.value < 0)
  1101.             bgmvolume.value = 0;
  1102.         if (bgmvolume.value > 1)
  1103.             bgmvolume.value = 1;
  1104.         Cvar_SetValue ("bgmvolume", bgmvolume.value);
  1105.         break;
  1106.     case 7:    // sfx volume
  1107.         volume.value += dir * 0.1;
  1108.         if (volume.value < 0)
  1109.             volume.value = 0;
  1110.         if (volume.value > 1)
  1111.             volume.value = 1;
  1112.         Cvar_SetValue ("volume", volume.value);
  1113.         break;
  1114.  
  1115.     case 8:    // allways run
  1116.         if (cl_forwardspeed.value > 200)
  1117.         {
  1118.             Cvar_SetValue ("cl_forwardspeed", 200);
  1119.             Cvar_SetValue ("cl_backspeed", 200);
  1120.         }
  1121.         else
  1122.         {
  1123.             Cvar_SetValue ("cl_forwardspeed", 400);
  1124.             Cvar_SetValue ("cl_backspeed", 400);
  1125.         }
  1126.         break;
  1127.  
  1128.     case 9:    // invert mouse
  1129.         Cvar_SetValue ("m_pitch", -m_pitch.value);
  1130.         break;
  1131.  
  1132.     case 10:    // lookspring
  1133.         Cvar_SetValue ("lookspring", !lookspring.value);
  1134.         break;
  1135.  
  1136.     case 11:    // lookstrafe
  1137.         Cvar_SetValue ("lookstrafe", !lookstrafe.value);
  1138.         break;
  1139.  
  1140. #ifdef _WIN32
  1141.     case 13:    // _windowed_mouse
  1142.         Cvar_SetValue ("_windowed_mouse", !_windowed_mouse.value);
  1143.         break;
  1144. #endif
  1145.     }
  1146. }
  1147.  
  1148.  
  1149. void M_DrawSlider (int x, int y, float range)
  1150. {
  1151.     int    i;
  1152.  
  1153.     if (range < 0)
  1154.         range = 0;
  1155.     if (range > 1)
  1156.         range = 1;
  1157.     M_DrawCharacter (x-8, y, 128);
  1158.     for (i=0 ; i<SLIDER_RANGE ; i++)
  1159.         M_DrawCharacter (x + i*8, y, 129);
  1160.     M_DrawCharacter (x+i*8, y, 130);
  1161.     M_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);
  1162. }
  1163.  
  1164. void M_DrawCheckbox (int x, int y, int on)
  1165. {
  1166. #if 0
  1167.     if (on)
  1168.         M_DrawCharacter (x, y, 131);
  1169.     else
  1170.         M_DrawCharacter (x, y, 129);
  1171. #endif
  1172.     if (on)
  1173.         M_Print (x, y, "on");
  1174.     else
  1175.         M_Print (x, y, "off");
  1176. }
  1177.  
  1178. void M_Options_Draw (void)
  1179. {
  1180.     float        r;
  1181.     qpic_t    *p;
  1182.  
  1183.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  1184.     p = Draw_CachePic ("gfx/p_option.lmp");
  1185.     M_DrawPic ( (320-p->width)/2, 4, p);
  1186.  
  1187.     M_Print (16, 32, "    Customize controls");
  1188.     M_Print (16, 40, "         Go to console");
  1189.     M_Print (16, 48, "     Reset to defaults");
  1190.  
  1191.     M_Print (16, 56, "           Screen size");
  1192.     r = (scr_viewsize.value - 30) / (120 - 30);
  1193.     M_DrawSlider (220, 56, r);
  1194.  
  1195.     M_Print (16, 64, "            Brightness");
  1196.     r = (1.0 - v_gamma.value) / 0.5;
  1197.     M_DrawSlider (220, 64, r);
  1198.  
  1199.     M_Print (16, 72, "           Mouse Speed");
  1200.     r = (sensitivity.value - 1)/10;
  1201.     M_DrawSlider (220, 72, r);
  1202.  
  1203.     M_Print (16, 80, "       CD Music Volume");
  1204.     r = bgmvolume.value;
  1205.     M_DrawSlider (220, 80, r);
  1206.  
  1207.     M_Print (16, 88, "          Sound Volume");
  1208.     r = volume.value;
  1209.     M_DrawSlider (220, 88, r);
  1210.  
  1211.     M_Print (16, 96,  "            Always Run");
  1212.     M_DrawCheckbox (220, 96, cl_forwardspeed.value > 200);
  1213.  
  1214.     M_Print (16, 104, "          Invert Mouse");
  1215.     M_DrawCheckbox (220, 104, m_pitch.value < 0);
  1216.  
  1217.     M_Print (16, 112, "            Lookspring");
  1218.     M_DrawCheckbox (220, 112, lookspring.value);
  1219.  
  1220.     M_Print (16, 120, "            Lookstrafe");
  1221.     M_DrawCheckbox (220, 120, lookstrafe.value);
  1222.  
  1223.     if (vid_menudrawfn)
  1224.         M_Print (16, 128, "         Video Options");
  1225.  
  1226. #ifdef _WIN32
  1227.     if (modestate == MS_WINDOWED)
  1228.     {
  1229.         M_Print (16, 136, "             Use Mouse");
  1230.         M_DrawCheckbox (220, 136, _windowed_mouse.value);
  1231.     }
  1232. #endif
  1233.  
  1234. // cursor
  1235.     M_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));
  1236. }
  1237.  
  1238.  
  1239. void M_Options_Key (int k)
  1240. {
  1241.     switch (k)
  1242.     {
  1243.     case K_ESCAPE:
  1244.         M_Menu_Main_f ();
  1245.         break;
  1246.  
  1247.     case K_ENTER:
  1248.         m_entersound = true;
  1249.         switch (options_cursor)
  1250.         {
  1251.         case 0:
  1252.             M_Menu_Keys_f ();
  1253.             break;
  1254.         case 1:
  1255.             m_state = m_none;
  1256.             Con_ToggleConsole_f ();
  1257.             break;
  1258.         case 2:
  1259.             Cbuf_AddText ("exec default.cfg\n");
  1260.             break;
  1261.         case 12:
  1262.             M_Menu_Video_f ();
  1263.             break;
  1264.         default:
  1265.             M_AdjustSliders (1);
  1266.             break;
  1267.         }
  1268.         return;
  1269.  
  1270.     case K_UPARROW:
  1271.         S_LocalSound ("misc/menu1.wav");
  1272.         options_cursor--;
  1273.         if (options_cursor < 0)
  1274.             options_cursor = OPTIONS_ITEMS-1;
  1275.         break;
  1276.  
  1277.     case K_DOWNARROW:
  1278.         S_LocalSound ("misc/menu1.wav");
  1279.         options_cursor++;
  1280.         if (options_cursor >= OPTIONS_ITEMS)
  1281.             options_cursor = 0;
  1282.         break;
  1283.  
  1284.     case K_LEFTARROW:
  1285.         M_AdjustSliders (-1);
  1286.         break;
  1287.  
  1288.     case K_RIGHTARROW:
  1289.         M_AdjustSliders (1);
  1290.         break;
  1291.     }
  1292.  
  1293.     if (options_cursor == 12 && vid_menudrawfn == NULL)
  1294.     {
  1295.         if (k == K_UPARROW)
  1296.             options_cursor = 11;
  1297.         else
  1298.             options_cursor = 0;
  1299.     }
  1300.  
  1301. #ifdef _WIN32
  1302.     if ((options_cursor == 13) && (modestate != MS_WINDOWED))
  1303.     {
  1304.         if (k == K_UPARROW)
  1305.             options_cursor = 12;
  1306.         else
  1307.             options_cursor = 0;
  1308.     }
  1309. #endif
  1310. }
  1311.  
  1312. //=============================================================================
  1313. /* KEYS MENU */
  1314.  
  1315. char *bindnames[][2] =
  1316. {
  1317. {"+attack",         "attack"},
  1318. {"impulse 10",         "change weapon"},
  1319. {"+jump",             "jump / swim up"},
  1320. {"+forward",         "walk forward"},
  1321. {"+back",             "backpedal"},
  1322. {"+left",             "turn left"},
  1323. {"+right",             "turn right"},
  1324. {"+speed",             "run"},
  1325. {"+moveleft",         "step left"},
  1326. {"+moveright",         "step right"},
  1327. {"+strafe",         "sidestep"},
  1328. {"+lookup",         "look up"},
  1329. {"+lookdown",         "look down"},
  1330. {"centerview",         "center view"},
  1331. {"+mlook",             "mouse look"},
  1332. {"+klook",             "keyboard look"},
  1333. {"+moveup",            "swim up"},
  1334. {"+movedown",        "swim down"}
  1335. };
  1336.  
  1337. #define    NUMCOMMANDS    (sizeof(bindnames)/sizeof(bindnames[0]))
  1338.  
  1339. int        keys_cursor;
  1340. int        bind_grab;
  1341.  
  1342. void M_Menu_Keys_f (void)
  1343. {
  1344.     key_dest = key_menu;
  1345.     m_state = m_keys;
  1346.     m_entersound = true;
  1347. }
  1348.  
  1349.  
  1350. void M_FindKeysForCommand (char *command, int *twokeys)
  1351. {
  1352.     int        count;
  1353.     int        j;
  1354.     int        l;
  1355.     char    *b;
  1356.  
  1357.     twokeys[0] = twokeys[1] = -1;
  1358.     l = strlen(command);
  1359.     count = 0;
  1360.  
  1361.     for (j=0 ; j<256 ; j++)
  1362.     {
  1363.         b = keybindings[j];
  1364.         if (!b)
  1365.             continue;
  1366.         if (!strncmp (b, command, l) )
  1367.         {
  1368.             twokeys[count] = j;
  1369.             count++;
  1370.             if (count == 2)
  1371.                 break;
  1372.         }
  1373.     }
  1374. }
  1375.  
  1376. void M_UnbindCommand (char *command)
  1377. {
  1378.     int        j;
  1379.     int        l;
  1380.     char    *b;
  1381.  
  1382.     l = strlen(command);
  1383.  
  1384.     for (j=0 ; j<256 ; j++)
  1385.     {
  1386.         b = keybindings[j];
  1387.         if (!b)
  1388.             continue;
  1389.         if (!strncmp (b, command, l) )
  1390.             Key_SetBinding (j, "");
  1391.     }
  1392. }
  1393.  
  1394.  
  1395. void M_Keys_Draw (void)
  1396. {
  1397.     int        i, l;
  1398.     int        keys[2];
  1399.     char    *name;
  1400.     int        x, y;
  1401.     qpic_t    *p;
  1402.  
  1403.     p = Draw_CachePic ("gfx/ttl_cstm.lmp");
  1404.     M_DrawPic ( (320-p->width)/2, 4, p);
  1405.  
  1406.     if (bind_grab)
  1407.         M_Print (12, 32, "Press a key or button for this action");
  1408.     else
  1409.         M_Print (18, 32, "Enter to change, backspace to clear");
  1410.  
  1411. // search for known bindings
  1412.     for (i=0 ; i<NUMCOMMANDS ; i++)
  1413.     {
  1414.         y = 48 + 8*i;
  1415.  
  1416.         M_Print (16, y, bindnames[i][1]);
  1417.  
  1418.         l = strlen (bindnames[i][0]);
  1419.  
  1420.         M_FindKeysForCommand (bindnames[i][0], keys);
  1421.  
  1422.         if (keys[0] == -1)
  1423.         {
  1424.             M_Print (140, y, "???");
  1425.         }
  1426.         else
  1427.         {
  1428.             name = Key_KeynumToString (keys[0]);
  1429.             M_Print (140, y, name);
  1430.             x = strlen(name) * 8;
  1431.             if (keys[1] != -1)
  1432.             {
  1433.                 M_Print (140 + x + 8, y, "or");
  1434.                 M_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));
  1435.             }
  1436.         }
  1437.     }
  1438.  
  1439.     if (bind_grab)
  1440.         M_DrawCharacter (130, 48 + keys_cursor*8, '=');
  1441.     else
  1442.         M_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));
  1443. }
  1444.  
  1445.  
  1446. void M_Keys_Key (int k)
  1447. {
  1448.     char    cmd[80];
  1449.     int        keys[2];
  1450.  
  1451.     if (bind_grab)
  1452.     {    // defining a key
  1453.         S_LocalSound ("misc/menu1.wav");
  1454.         if (k == K_ESCAPE)
  1455.         {
  1456.             bind_grab = false;
  1457.         }
  1458.         else if (k != '`')
  1459.         {
  1460.             sprintf (cmd, "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
  1461.             Cbuf_InsertText (cmd);
  1462.         }
  1463.  
  1464.         bind_grab = false;
  1465.         return;
  1466.     }
  1467.  
  1468.     switch (k)
  1469.     {
  1470.     case K_ESCAPE:
  1471.         M_Menu_Options_f ();
  1472.         break;
  1473.  
  1474.     case K_LEFTARROW:
  1475.     case K_UPARROW:
  1476.         S_LocalSound ("misc/menu1.wav");
  1477.         keys_cursor--;
  1478.         if (keys_cursor < 0)
  1479.             keys_cursor = NUMCOMMANDS-1;
  1480.         break;
  1481.  
  1482.     case K_DOWNARROW:
  1483.     case K_RIGHTARROW:
  1484.         S_LocalSound ("misc/menu1.wav");
  1485.         keys_cursor++;
  1486.         if (keys_cursor >= NUMCOMMANDS)
  1487.             keys_cursor = 0;
  1488.         break;
  1489.  
  1490.     case K_ENTER:        // go into bind mode
  1491.         M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
  1492.         S_LocalSound ("misc/menu2.wav");
  1493.         if (keys[1] != -1)
  1494.             M_UnbindCommand (bindnames[keys_cursor][0]);
  1495.         bind_grab = true;
  1496.         break;
  1497.  
  1498.     case K_BACKSPACE:        // delete bindings
  1499.     case K_DEL:                // delete bindings
  1500.         S_LocalSound ("misc/menu2.wav");
  1501.         M_UnbindCommand (bindnames[keys_cursor][0]);
  1502.         break;
  1503.     }
  1504. }
  1505.  
  1506. //=============================================================================
  1507. /* VIDEO MENU */
  1508.  
  1509. void M_Menu_Video_f (void)
  1510. {
  1511.     key_dest = key_menu;
  1512.     m_state = m_video;
  1513.     m_entersound = true;
  1514. }
  1515.  
  1516.  
  1517. void M_Video_Draw (void)
  1518. {
  1519.     (*vid_menudrawfn) ();
  1520. }
  1521.  
  1522.  
  1523. void M_Video_Key (int key)
  1524. {
  1525.     (*vid_menukeyfn) (key);
  1526. }
  1527.  
  1528. //=============================================================================
  1529. /* HELP MENU */
  1530.  
  1531. int        help_page;
  1532. #define    NUM_HELP_PAGES    6
  1533.  
  1534.  
  1535. void M_Menu_Help_f (void)
  1536. {
  1537.     key_dest = key_menu;
  1538.     m_state = m_help;
  1539.     m_entersound = true;
  1540.     help_page = 0;
  1541. }
  1542.  
  1543.  
  1544.  
  1545. void M_Help_Draw (void)
  1546. {
  1547.     M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) );
  1548. }
  1549.  
  1550.  
  1551. void M_Help_Key (int key)
  1552. {
  1553.     switch (key)
  1554.     {
  1555.     case K_ESCAPE:
  1556.         M_Menu_Main_f ();
  1557.         break;
  1558.  
  1559.     case K_UPARROW:
  1560.     case K_RIGHTARROW:
  1561.         m_entersound = true;
  1562.         if (++help_page >= NUM_HELP_PAGES)
  1563.             help_page = 0;
  1564.         break;
  1565.  
  1566.     case K_DOWNARROW:
  1567.     case K_LEFTARROW:
  1568.         m_entersound = true;
  1569.         if (--help_page < 0)
  1570.             help_page = NUM_HELP_PAGES-1;
  1571.         break;
  1572.     }
  1573.  
  1574. }
  1575.  
  1576. //=============================================================================
  1577. /* QUIT MENU */
  1578.  
  1579. int        msgNumber;
  1580. int        m_quit_prevstate;
  1581. qboolean    wasInMenus;
  1582.  
  1583. #ifndef    _WIN32
  1584. char *quitMessage [] = 
  1585. {
  1586. /* .........1.........2.... */
  1587.   "  Are you gonna quit    ",
  1588.   "  this game just like   ",
  1589.   "   everything else?     ",
  1590.   "                        ",
  1591.  
  1592.   " Milord, methinks that  ",
  1593.   "   thou art a lowly     ",
  1594.   " quitter. Is this true? ",
  1595.   "                        ",
  1596.  
  1597.   " Do I need to bust your ",
  1598.   "  face open for trying  ",
  1599.   "        to quit?        ",
  1600.   "                        ",
  1601.  
  1602.   " Man, I oughta smack you",
  1603.   "   for trying to quit!  ",
  1604.   "     Press Y to get     ",
  1605.   "      smacked out.      ",
  1606.  
  1607.   " Press Y to quit like a ",
  1608.   "   big loser in life.   ",
  1609.   "  Press N to stay proud ",
  1610.   "    and successful!     ",
  1611.  
  1612.   "   If you press Y to    ",
  1613.   "  quit, I will summon   ",
  1614.   "  Satan all over your   ",
  1615.   "      hard drive!       ",
  1616.  
  1617.   "  Um, Asmodeus dislikes ",
  1618.   " his children trying to ",
  1619.   " quit. Press Y to return",
  1620.   "   to your Tinkertoys.  ",
  1621.  
  1622.   "  If you quit now, I'll ",
  1623.   "  throw a blanket-party ",
  1624.   "   for you next time!   ",
  1625.   "                        "
  1626. };
  1627. #endif
  1628.  
  1629. void M_Menu_Quit_f (void)
  1630. {
  1631.     if (m_state == m_quit)
  1632.         return;
  1633.     wasInMenus = (key_dest == key_menu);
  1634.     key_dest = key_menu;
  1635.     m_quit_prevstate = m_state;
  1636.     m_state = m_quit;
  1637.     m_entersound = true;
  1638.     msgNumber = rand()&7;
  1639. }
  1640.  
  1641.  
  1642. void M_Quit_Key (int key)
  1643. {
  1644.     switch (key)
  1645.     {
  1646.     case K_ESCAPE:
  1647.     case 'n':
  1648.     case 'N':
  1649.         if (wasInMenus)
  1650.         {
  1651.             m_state = m_quit_prevstate;
  1652.             m_entersound = true;
  1653.         }
  1654.         else
  1655.         {
  1656.             key_dest = key_game;
  1657.             m_state = m_none;
  1658.         }
  1659.         break;
  1660.  
  1661.     case 'Y':
  1662.     case 'y':
  1663.         key_dest = key_console;
  1664.         Host_Quit_f ();
  1665.         break;
  1666.  
  1667.     default:
  1668.         break;
  1669.     }
  1670.  
  1671. }
  1672.  
  1673.  
  1674. void M_Quit_Draw (void)
  1675. {
  1676.     if (wasInMenus)
  1677.     {
  1678.         m_state = m_quit_prevstate;
  1679.         m_recursiveDraw = true;
  1680.         M_Draw ();
  1681.         m_state = m_quit;
  1682.     }
  1683.  
  1684. #ifdef _WIN32
  1685.     M_DrawTextBox (0, 0, 38, 23);
  1686.     M_PrintWhite (16, 12,  "  Quake version 1.09 by id Software\n\n");
  1687.     M_PrintWhite (16, 28,  "Programming        Art \n");
  1688.     M_Print (16, 36,  " John Carmack       Adrian Carmack\n");
  1689.     M_Print (16, 44,  " Michael Abrash     Kevin Cloud\n");
  1690.     M_Print (16, 52,  " John Cash          Paul Steed\n");
  1691.     M_Print (16, 60,  " Dave 'Zoid' Kirsch\n");
  1692.     M_PrintWhite (16, 68,  "Design             Biz\n");
  1693.     M_Print (16, 76,  " John Romero        Jay Wilbur\n");
  1694.     M_Print (16, 84,  " Sandy Petersen     Mike Wilson\n");
  1695.     M_Print (16, 92,  " American McGee     Donna Jackson\n");
  1696.     M_Print (16, 100,  " Tim Willits        Todd Hollenshead\n");
  1697.     M_PrintWhite (16, 108, "Support            Projects\n");
  1698.     M_Print (16, 116, " Barrett Alexander  Shawn Green\n");
  1699.     M_PrintWhite (16, 124, "Sound Effects\n");
  1700.     M_Print (16, 132, " Trent Reznor and Nine Inch Nails\n\n");
  1701.     M_PrintWhite (16, 140, "Quake is a trademark of Id Software,\n");
  1702.     M_PrintWhite (16, 148, "inc., (c)1996 Id Software, inc. All\n");
  1703.     M_PrintWhite (16, 156, "rights reserved. NIN logo is a\n");
  1704.     M_PrintWhite (16, 164, "registered trademark licensed to\n");
  1705.     M_PrintWhite (16, 172, "Nothing Interactive, Inc. All rights\n");
  1706.     M_PrintWhite (16, 180, "reserved. Press y to exit\n");
  1707. #else
  1708.     M_DrawTextBox (56, 76, 24, 4);
  1709.     M_Print (64, 84,  quitMessage[msgNumber*4+0]);
  1710.     M_Print (64, 92,  quitMessage[msgNumber*4+1]);
  1711.     M_Print (64, 100, quitMessage[msgNumber*4+2]);
  1712.     M_Print (64, 108, quitMessage[msgNumber*4+3]);
  1713. #endif
  1714. }
  1715.  
  1716. //=============================================================================
  1717.  
  1718. /* SERIAL CONFIG MENU */
  1719.  
  1720. int        serialConfig_cursor;
  1721. int        serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132};
  1722. #define    NUM_SERIALCONFIG_CMDS    6
  1723.  
  1724. static int ISA_uarts[]    = {0x3f8,0x2f8,0x3e8,0x2e8};
  1725. static int ISA_IRQs[]    = {4,3,4,3};
  1726. int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600};
  1727.  
  1728. int        serialConfig_comport;
  1729. int        serialConfig_irq ;
  1730. int        serialConfig_baud;
  1731. char    serialConfig_phone[16];
  1732.  
  1733. void M_Menu_SerialConfig_f (void)
  1734. {
  1735.     int        n;
  1736.     int        port;
  1737.     int        baudrate;
  1738.     qboolean    useModem;
  1739.  
  1740.     key_dest = key_menu;
  1741.     m_state = m_serialconfig;
  1742.     m_entersound = true;
  1743.     if (JoiningGame && SerialConfig)
  1744.         serialConfig_cursor = 4;
  1745.     else
  1746.         serialConfig_cursor = 5;
  1747.  
  1748.     (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem);
  1749.  
  1750.     // map uart's port to COMx
  1751.     for (n = 0; n < 4; n++)
  1752.         if (ISA_uarts[n] == port)
  1753.             break;
  1754.     if (n == 4)
  1755.     {
  1756.         n = 0;
  1757.         serialConfig_irq = 4;
  1758.     }
  1759.     serialConfig_comport = n + 1;
  1760.  
  1761.     // map baudrate to index
  1762.     for (n = 0; n < 6; n++)
  1763.         if (serialConfig_baudrate[n] == baudrate)
  1764.             break;
  1765.     if (n == 6)
  1766.         n = 5;
  1767.     serialConfig_baud = n;
  1768.  
  1769.     m_return_onerror = false;
  1770.     m_return_reason[0] = 0;
  1771. }
  1772.  
  1773.  
  1774. void M_SerialConfig_Draw (void)
  1775. {
  1776.     qpic_t    *p;
  1777.     int        basex;
  1778.     char    *startJoin;
  1779.     char    *directModem;
  1780.  
  1781.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  1782.     p = Draw_CachePic ("gfx/p_multi.lmp");
  1783.     basex = (320-p->width)/2;
  1784.     M_DrawPic (basex, 4, p);
  1785.  
  1786.     if (StartingGame)
  1787.         startJoin = "New Game";
  1788.     else
  1789.         startJoin = "Join Game";
  1790.     if (SerialConfig)
  1791.         directModem = "Modem";
  1792.     else
  1793.         directModem = "Direct Connect";
  1794.     M_Print (basex, 32, va ("%s - %s", startJoin, directModem));
  1795.     basex += 8;
  1796.  
  1797.     M_Print (basex, serialConfig_cursor_table[0], "Port");
  1798.     M_DrawTextBox (160, 40, 4, 1);
  1799.     M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport));
  1800.  
  1801.     M_Print (basex, serialConfig_cursor_table[1], "IRQ");
  1802.     M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1);
  1803.     M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq));
  1804.  
  1805.     M_Print (basex, serialConfig_cursor_table[2], "Baud");
  1806.     M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1);
  1807.     M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud]));
  1808.  
  1809.     if (SerialConfig)
  1810.     {
  1811.         M_Print (basex, serialConfig_cursor_table[3], "Modem Setup...");
  1812.         if (JoiningGame)
  1813.         {
  1814.             M_Print (basex, serialConfig_cursor_table[4], "Phone number");
  1815.             M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1);
  1816.             M_Print (168, serialConfig_cursor_table[4], serialConfig_phone);
  1817.         }
  1818.     }
  1819.  
  1820.     if (JoiningGame)
  1821.     {
  1822.         M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1);
  1823.         M_Print (basex+8, serialConfig_cursor_table[5], "Connect");
  1824.     }
  1825.     else
  1826.     {
  1827.         M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1);
  1828.         M_Print (basex+8, serialConfig_cursor_table[5], "OK");
  1829.     }
  1830.  
  1831.     M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1));
  1832.  
  1833.     if (serialConfig_cursor == 4)
  1834.         M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1));
  1835.  
  1836.     if (*m_return_reason)
  1837.         M_PrintWhite (basex, 148, m_return_reason);
  1838. }
  1839.  
  1840.  
  1841. void M_SerialConfig_Key (int key)
  1842. {
  1843.     int        l;
  1844.  
  1845.     switch (key)
  1846.     {
  1847.     case K_ESCAPE:
  1848.         M_Menu_Net_f ();
  1849.         break;
  1850.  
  1851.     case K_UPARROW:
  1852.         S_LocalSound ("misc/menu1.wav");
  1853.         serialConfig_cursor--;
  1854.         if (serialConfig_cursor < 0)
  1855.             serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1;
  1856.         break;
  1857.  
  1858.     case K_DOWNARROW:
  1859.         S_LocalSound ("misc/menu1.wav");
  1860.         serialConfig_cursor++;
  1861.         if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS)
  1862.             serialConfig_cursor = 0;
  1863.         break;
  1864.  
  1865.     case K_LEFTARROW:
  1866.         if (serialConfig_cursor > 2)
  1867.             break;
  1868.         S_LocalSound ("misc/menu3.wav");
  1869.  
  1870.         if (serialConfig_cursor == 0)
  1871.         {
  1872.             serialConfig_comport--;
  1873.             if (serialConfig_comport == 0)
  1874.                 serialConfig_comport = 4;
  1875.             serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
  1876.         }
  1877.  
  1878.         if (serialConfig_cursor == 1)
  1879.         {
  1880.             serialConfig_irq--;
  1881.             if (serialConfig_irq == 6)
  1882.                 serialConfig_irq = 5;
  1883.             if (serialConfig_irq == 1)
  1884.                 serialConfig_irq = 7;
  1885.         }
  1886.  
  1887.         if (serialConfig_cursor == 2)
  1888.         {
  1889.             serialConfig_baud--;
  1890.             if (serialConfig_baud < 0)
  1891.                 serialConfig_baud = 5;
  1892.         }
  1893.  
  1894.         break;
  1895.  
  1896.     case K_RIGHTARROW:
  1897.         if (serialConfig_cursor > 2)
  1898.             break;
  1899. forward:
  1900.         S_LocalSound ("misc/menu3.wav");
  1901.  
  1902.         if (serialConfig_cursor == 0)
  1903.         {
  1904.             serialConfig_comport++;
  1905.             if (serialConfig_comport > 4)
  1906.                 serialConfig_comport = 1;
  1907.             serialConfig_irq = ISA_IRQs[serialConfig_comport-1];
  1908.         }
  1909.  
  1910.         if (serialConfig_cursor == 1)
  1911.         {
  1912.             serialConfig_irq++;
  1913.             if (serialConfig_irq == 6)
  1914.                 serialConfig_irq = 7;
  1915.             if (serialConfig_irq == 8)
  1916.                 serialConfig_irq = 2;
  1917.         }
  1918.  
  1919.         if (serialConfig_cursor == 2)
  1920.         {
  1921.             serialConfig_baud++;
  1922.             if (serialConfig_baud > 5)
  1923.                 serialConfig_baud = 0;
  1924.         }
  1925.  
  1926.         break;
  1927.  
  1928.     case K_ENTER:
  1929.         if (serialConfig_cursor < 3)
  1930.             goto forward;
  1931.  
  1932.         m_entersound = true;
  1933.  
  1934.         if (serialConfig_cursor == 3)
  1935.         {
  1936.             (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
  1937.  
  1938.             M_Menu_ModemConfig_f ();
  1939.             break;
  1940.         }
  1941.  
  1942.         if (serialConfig_cursor == 4)
  1943.         {
  1944.             serialConfig_cursor = 5;
  1945.             break;
  1946.         }
  1947.  
  1948.         // serialConfig_cursor == 5 (OK/CONNECT)
  1949.         (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig);
  1950.  
  1951.         M_ConfigureNetSubsystem ();
  1952.  
  1953.         if (StartingGame)
  1954.         {
  1955.             M_Menu_GameOptions_f ();
  1956.             break;
  1957.         }
  1958.  
  1959.         m_return_state = m_state;
  1960.         m_return_onerror = true;
  1961.         key_dest = key_game;
  1962.         m_state = m_none;
  1963.  
  1964.         if (SerialConfig)
  1965.             Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone));
  1966.         else
  1967.             Cbuf_AddText ("connect\n");
  1968.         break;
  1969.  
  1970.     case K_BACKSPACE:
  1971.         if (serialConfig_cursor == 4)
  1972.         {
  1973.             if (strlen(serialConfig_phone))
  1974.                 serialConfig_phone[strlen(serialConfig_phone)-1] = 0;
  1975.         }
  1976.         break;
  1977.  
  1978.     default:
  1979.         if (key < 32 || key > 127)
  1980.             break;
  1981.         if (serialConfig_cursor == 4)
  1982.         {
  1983.             l = strlen(serialConfig_phone);
  1984.             if (l < 15)
  1985.             {
  1986.                 serialConfig_phone[l+1] = 0;
  1987.                 serialConfig_phone[l] = key;
  1988.             }
  1989.         }
  1990.     }
  1991.  
  1992.     if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4))
  1993.         if (key == K_UPARROW)
  1994.             serialConfig_cursor = 2;
  1995.         else
  1996.             serialConfig_cursor = 5;
  1997.  
  1998.     if (SerialConfig && StartingGame && serialConfig_cursor == 4)
  1999.         if (key == K_UPARROW)
  2000.             serialConfig_cursor = 3;
  2001.         else
  2002.             serialConfig_cursor = 5;
  2003. }
  2004.  
  2005. //=============================================================================
  2006. /* MODEM CONFIG MENU */
  2007.  
  2008. int        modemConfig_cursor;
  2009. int        modemConfig_cursor_table [] = {40, 56, 88, 120, 156};
  2010. #define NUM_MODEMCONFIG_CMDS    5
  2011.  
  2012. char    modemConfig_dialing;
  2013. char    modemConfig_clear [16];
  2014. char    modemConfig_init [32];
  2015. char    modemConfig_hangup [16];
  2016.  
  2017. void M_Menu_ModemConfig_f (void)
  2018. {
  2019.     key_dest = key_menu;
  2020.     m_state = m_modemconfig;
  2021.     m_entersound = true;
  2022.     (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup);
  2023. }
  2024.  
  2025.  
  2026. void M_ModemConfig_Draw (void)
  2027. {
  2028.     qpic_t    *p;
  2029.     int        basex;
  2030.  
  2031.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2032.     p = Draw_CachePic ("gfx/p_multi.lmp");
  2033.     basex = (320-p->width)/2;
  2034.     M_DrawPic (basex, 4, p);
  2035.     basex += 8;
  2036.  
  2037.     if (modemConfig_dialing == 'P')
  2038.         M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing");
  2039.     else
  2040.         M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing");
  2041.  
  2042.     M_Print (basex, modemConfig_cursor_table[1], "Clear");
  2043.     M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1);
  2044.     M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear);
  2045.     if (modemConfig_cursor == 1)
  2046.         M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1));
  2047.  
  2048.     M_Print (basex, modemConfig_cursor_table[2], "Init");
  2049.     M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1);
  2050.     M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init);
  2051.     if (modemConfig_cursor == 2)
  2052.         M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1));
  2053.  
  2054.     M_Print (basex, modemConfig_cursor_table[3], "Hangup");
  2055.     M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1);
  2056.     M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup);
  2057.     if (modemConfig_cursor == 3)
  2058.         M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1));
  2059.  
  2060.     M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1);
  2061.     M_Print (basex+8, modemConfig_cursor_table[4], "OK");
  2062.  
  2063.     M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1));
  2064. }
  2065.  
  2066.  
  2067. void M_ModemConfig_Key (int key)
  2068. {
  2069.     int        l;
  2070.  
  2071.     switch (key)
  2072.     {
  2073.     case K_ESCAPE:
  2074.         M_Menu_SerialConfig_f ();
  2075.         break;
  2076.  
  2077.     case K_UPARROW:
  2078.         S_LocalSound ("misc/menu1.wav");
  2079.         modemConfig_cursor--;
  2080.         if (modemConfig_cursor < 0)
  2081.             modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1;
  2082.         break;
  2083.  
  2084.     case K_DOWNARROW:
  2085.         S_LocalSound ("misc/menu1.wav");
  2086.         modemConfig_cursor++;
  2087.         if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS)
  2088.             modemConfig_cursor = 0;
  2089.         break;
  2090.  
  2091.     case K_LEFTARROW:
  2092.     case K_RIGHTARROW:
  2093.         if (modemConfig_cursor == 0)
  2094.         {
  2095.             if (modemConfig_dialing == 'P')
  2096.                 modemConfig_dialing = 'T';
  2097.             else
  2098.                 modemConfig_dialing = 'P';
  2099.             S_LocalSound ("misc/menu1.wav");
  2100.         }
  2101.         break;
  2102.  
  2103.     case K_ENTER:
  2104.         if (modemConfig_cursor == 0)
  2105.         {
  2106.             if (modemConfig_dialing == 'P')
  2107.                 modemConfig_dialing = 'T';
  2108.             else
  2109.                 modemConfig_dialing = 'P';
  2110.             m_entersound = true;
  2111.         }
  2112.  
  2113.         if (modemConfig_cursor == 4)
  2114.         {
  2115.             (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup);
  2116.             m_entersound = true;
  2117.             M_Menu_SerialConfig_f ();
  2118.         }
  2119.         break;
  2120.  
  2121.     case K_BACKSPACE:
  2122.         if (modemConfig_cursor == 1)
  2123.         {
  2124.             if (strlen(modemConfig_clear))
  2125.                 modemConfig_clear[strlen(modemConfig_clear)-1] = 0;
  2126.         }
  2127.  
  2128.         if (modemConfig_cursor == 2)
  2129.         {
  2130.             if (strlen(modemConfig_init))
  2131.                 modemConfig_init[strlen(modemConfig_init)-1] = 0;
  2132.         }
  2133.  
  2134.         if (modemConfig_cursor == 3)
  2135.         {
  2136.             if (strlen(modemConfig_hangup))
  2137.                 modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0;
  2138.         }
  2139.         break;
  2140.  
  2141.     default:
  2142.         if (key < 32 || key > 127)
  2143.             break;
  2144.  
  2145.         if (modemConfig_cursor == 1)
  2146.         {
  2147.             l = strlen(modemConfig_clear);
  2148.             if (l < 15)
  2149.             {
  2150.                 modemConfig_clear[l+1] = 0;
  2151.                 modemConfig_clear[l] = key;
  2152.             }
  2153.         }
  2154.  
  2155.         if (modemConfig_cursor == 2)
  2156.         {
  2157.             l = strlen(modemConfig_init);
  2158.             if (l < 29)
  2159.             {
  2160.                 modemConfig_init[l+1] = 0;
  2161.                 modemConfig_init[l] = key;
  2162.             }
  2163.         }
  2164.  
  2165.         if (modemConfig_cursor == 3)
  2166.         {
  2167.             l = strlen(modemConfig_hangup);
  2168.             if (l < 15)
  2169.             {
  2170.                 modemConfig_hangup[l+1] = 0;
  2171.                 modemConfig_hangup[l] = key;
  2172.             }
  2173.         }
  2174.     }
  2175. }
  2176.  
  2177. //=============================================================================
  2178. /* LAN CONFIG MENU */
  2179.  
  2180. int        lanConfig_cursor = -1;
  2181. int        lanConfig_cursor_table [] = {72, 92, 124};
  2182. #define NUM_LANCONFIG_CMDS    3
  2183.  
  2184. int     lanConfig_port;
  2185. char    lanConfig_portname[6];
  2186. char    lanConfig_joinname[22];
  2187.  
  2188. void M_Menu_LanConfig_f (void)
  2189. {
  2190.     key_dest = key_menu;
  2191.     m_state = m_lanconfig;
  2192.     m_entersound = true;
  2193.     if (lanConfig_cursor == -1)
  2194.     {
  2195.         if (JoiningGame && TCPIPConfig)
  2196.             lanConfig_cursor = 2;
  2197.         else
  2198.             lanConfig_cursor = 1;
  2199.     }
  2200.     if (StartingGame && lanConfig_cursor == 2)
  2201.         lanConfig_cursor = 1;
  2202.     lanConfig_port = DEFAULTnet_hostport;
  2203.     sprintf(lanConfig_portname, "%u", lanConfig_port);
  2204.  
  2205.     m_return_onerror = false;
  2206.     m_return_reason[0] = 0;
  2207. }
  2208.  
  2209.  
  2210. void M_LanConfig_Draw (void)
  2211. {
  2212.     qpic_t    *p;
  2213.     int        basex;
  2214.     char    *startJoin;
  2215.     char    *protocol;
  2216.  
  2217.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2218.     p = Draw_CachePic ("gfx/p_multi.lmp");
  2219.     basex = (320-p->width)/2;
  2220.     M_DrawPic (basex, 4, p);
  2221.  
  2222.     if (StartingGame)
  2223.         startJoin = "New Game";
  2224.     else
  2225.         startJoin = "Join Game";
  2226.     if (IPXConfig)
  2227.         protocol = "IPX";
  2228.     else
  2229.         protocol = "TCP/IP";
  2230.     M_Print (basex, 32, va ("%s - %s", startJoin, protocol));
  2231.     basex += 8;
  2232.  
  2233.     M_Print (basex, 52, "Address:");
  2234.     if (IPXConfig)
  2235.         M_Print (basex+9*8, 52, my_ipx_address);
  2236.     else
  2237.         M_Print (basex+9*8, 52, my_tcpip_address);
  2238.  
  2239.     M_Print (basex, lanConfig_cursor_table[0], "Port");
  2240.     M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);
  2241.     M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);
  2242.  
  2243.     if (JoiningGame)
  2244.     {
  2245.         M_Print (basex, lanConfig_cursor_table[1], "Search for local games...");
  2246.         M_Print (basex, 108, "Join game at:");
  2247.         M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1);
  2248.         M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname);
  2249.     }
  2250.     else
  2251.     {
  2252.         M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1);
  2253.         M_Print (basex+8, lanConfig_cursor_table[1], "OK");
  2254.     }
  2255.  
  2256.     M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));
  2257.  
  2258.     if (lanConfig_cursor == 0)
  2259.         M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));
  2260.  
  2261.     if (lanConfig_cursor == 2)
  2262.         M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1));
  2263.  
  2264.     if (*m_return_reason)
  2265.         M_PrintWhite (basex, 148, m_return_reason);
  2266. }
  2267.  
  2268.  
  2269. void M_LanConfig_Key (int key)
  2270. {
  2271.     int        l;
  2272.  
  2273.     switch (key)
  2274.     {
  2275.     case K_ESCAPE:
  2276.         M_Menu_Net_f ();
  2277.         break;
  2278.  
  2279.     case K_UPARROW:
  2280.         S_LocalSound ("misc/menu1.wav");
  2281.         lanConfig_cursor--;
  2282.         if (lanConfig_cursor < 0)
  2283.             lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
  2284.         break;
  2285.  
  2286.     case K_DOWNARROW:
  2287.         S_LocalSound ("misc/menu1.wav");
  2288.         lanConfig_cursor++;
  2289.         if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
  2290.             lanConfig_cursor = 0;
  2291.         break;
  2292.  
  2293.     case K_ENTER:
  2294.         if (lanConfig_cursor == 0)
  2295.             break;
  2296.  
  2297.         m_entersound = true;
  2298.  
  2299.         M_ConfigureNetSubsystem ();
  2300.  
  2301.         if (lanConfig_cursor == 1)
  2302.         {
  2303.             if (StartingGame)
  2304.             {
  2305.                 M_Menu_GameOptions_f ();
  2306.                 break;
  2307.             }
  2308.             M_Menu_Search_f();
  2309.             break;
  2310.         }
  2311.  
  2312.         if (lanConfig_cursor == 2)
  2313.         {
  2314.             m_return_state = m_state;
  2315.             m_return_onerror = true;
  2316.             key_dest = key_game;
  2317.             m_state = m_none;
  2318.             Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
  2319.             break;
  2320.         }
  2321.  
  2322.         break;
  2323.  
  2324.     case K_BACKSPACE:
  2325.         if (lanConfig_cursor == 0)
  2326.         {
  2327.             if (strlen(lanConfig_portname))
  2328.                 lanConfig_portname[strlen(lanConfig_portname)-1] = 0;
  2329.         }
  2330.  
  2331.         if (lanConfig_cursor == 2)
  2332.         {
  2333.             if (strlen(lanConfig_joinname))
  2334.                 lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;
  2335.         }
  2336.         break;
  2337.  
  2338.     default:
  2339.         if (key < 32 || key > 127)
  2340.             break;
  2341.  
  2342.         if (lanConfig_cursor == 2)
  2343.         {
  2344.             l = strlen(lanConfig_joinname);
  2345.             if (l < 21)
  2346.             {
  2347.                 lanConfig_joinname[l+1] = 0;
  2348.                 lanConfig_joinname[l] = key;
  2349.             }
  2350.         }
  2351.  
  2352.         if (key < '0' || key > '9')
  2353.             break;
  2354.         if (lanConfig_cursor == 0)
  2355.         {
  2356.             l = strlen(lanConfig_portname);
  2357.             if (l < 5)
  2358.             {
  2359.                 lanConfig_portname[l+1] = 0;
  2360.                 lanConfig_portname[l] = key;
  2361.             }
  2362.         }
  2363.     }
  2364.  
  2365.     if (StartingGame && lanConfig_cursor == 2)
  2366.         if (key == K_UPARROW)
  2367.             lanConfig_cursor = 1;
  2368.         else
  2369.             lanConfig_cursor = 0;
  2370.  
  2371.     l =  Q_atoi(lanConfig_portname);
  2372.     if (l > 65535)
  2373.         l = lanConfig_port;
  2374.     else
  2375.         lanConfig_port = l;
  2376.     sprintf(lanConfig_portname, "%u", lanConfig_port);
  2377. }
  2378.  
  2379. //=============================================================================
  2380. /* GAME OPTIONS MENU */
  2381.  
  2382. typedef struct
  2383. {
  2384.     char    *name;
  2385.     char    *description;
  2386. } level_t;
  2387.  
  2388. level_t        levels[] =
  2389. {
  2390.     {"start", "Entrance"},    // 0
  2391.  
  2392.     {"e1m1", "Slipgate Complex"},                // 1
  2393.     {"e1m2", "Castle of the Damned"},
  2394.     {"e1m3", "The Necropolis"},
  2395.     {"e1m4", "The Grisly Grotto"},
  2396.     {"e1m5", "Gloom Keep"},
  2397.     {"e1m6", "The Door To Chthon"},
  2398.     {"e1m7", "The House of Chthon"},
  2399.     {"e1m8", "Ziggurat Vertigo"},
  2400.  
  2401.     {"e2m1", "The Installation"},                // 9
  2402.     {"e2m2", "Ogre Citadel"},
  2403.     {"e2m3", "Crypt of Decay"},
  2404.     {"e2m4", "The Ebon Fortress"},
  2405.     {"e2m5", "The Wizard's Manse"},
  2406.     {"e2m6", "The Dismal Oubliette"},
  2407.     {"e2m7", "Underearth"},
  2408.  
  2409.     {"e3m1", "Termination Central"},            // 16
  2410.     {"e3m2", "The Vaults of Zin"},
  2411.     {"e3m3", "The Tomb of Terror"},
  2412.     {"e3m4", "Satan's Dark Delight"},
  2413.     {"e3m5", "Wind Tunnels"},
  2414.     {"e3m6", "Chambers of Torment"},
  2415.     {"e3m7", "The Haunted Halls"},
  2416.  
  2417.     {"e4m1", "The Sewage System"},                // 23
  2418.     {"e4m2", "The Tower of Despair"},
  2419.     {"e4m3", "The Elder God Shrine"},
  2420.     {"e4m4", "The Palace of Hate"},
  2421.     {"e4m5", "Hell's Atrium"},
  2422.     {"e4m6", "The Pain Maze"},
  2423.     {"e4m7", "Azure Agony"},
  2424.     {"e4m8", "The Nameless City"},
  2425.  
  2426.     {"end", "Shub-Niggurath's Pit"},            // 31
  2427.  
  2428.     {"dm1", "Place of Two Deaths"},                // 32
  2429.     {"dm2", "Claustrophobopolis"},
  2430.     {"dm3", "The Abandoned Base"},
  2431.     {"dm4", "The Bad Place"},
  2432.     {"dm5", "The Cistern"},
  2433.     {"dm6", "The Dark Zone"}
  2434. };
  2435.  
  2436. //MED 01/06/97 added hipnotic levels
  2437. level_t     hipnoticlevels[] =
  2438. {
  2439.    {"start", "Command HQ"},  // 0
  2440.  
  2441.    {"hip1m1", "The Pumping Station"},          // 1
  2442.    {"hip1m2", "Storage Facility"},
  2443.    {"hip1m3", "The Lost Mine"},
  2444.    {"hip1m4", "Research Facility"},
  2445.    {"hip1m5", "Military Complex"},
  2446.  
  2447.    {"hip2m1", "Ancient Realms"},          // 6
  2448.    {"hip2m2", "The Black Cathedral"},
  2449.    {"hip2m3", "The Catacombs"},
  2450.    {"hip2m4", "The Crypt"},
  2451.    {"hip2m5", "Mortum's Keep"},
  2452.    {"hip2m6", "The Gremlin's Domain"},
  2453.  
  2454.    {"hip3m1", "Tur Torment"},       // 12
  2455.    {"hip3m2", "Pandemonium"},
  2456.    {"hip3m3", "Limbo"},
  2457.    {"hip3m4", "The Gauntlet"},
  2458.  
  2459.    {"hipend", "Armagon's Lair"},       // 16
  2460.  
  2461.    {"hipdm1", "The Edge of Oblivion"}           // 17
  2462. };
  2463.  
  2464. //PGM 01/07/97 added rogue levels
  2465. //PGM 03/02/97 added dmatch level
  2466. level_t        roguelevels[] =
  2467. {
  2468.     {"start",    "Split Decision"},
  2469.     {"r1m1",    "Deviant's Domain"},
  2470.     {"r1m2",    "Dread Portal"},
  2471.     {"r1m3",    "Judgement Call"},
  2472.     {"r1m4",    "Cave of Death"},
  2473.     {"r1m5",    "Towers of Wrath"},
  2474.     {"r1m6",    "Temple of Pain"},
  2475.     {"r1m7",    "Tomb of the Overlord"},
  2476.     {"r2m1",    "Tempus Fugit"},
  2477.     {"r2m2",    "Elemental Fury I"},
  2478.     {"r2m3",    "Elemental Fury II"},
  2479.     {"r2m4",    "Curse of Osiris"},
  2480.     {"r2m5",    "Wizard's Keep"},
  2481.     {"r2m6",    "Blood Sacrifice"},
  2482.     {"r2m7",    "Last Bastion"},
  2483.     {"r2m8",    "Source of Evil"},
  2484.     {"ctf1",    "Division of Change"}
  2485. };
  2486.  
  2487. typedef struct
  2488. {
  2489.     char    *description;
  2490.     int        firstLevel;
  2491.     int        levels;
  2492. } episode_t;
  2493.  
  2494. episode_t    episodes[] =
  2495. {
  2496.     {"Welcome to Quake", 0, 1},
  2497.     {"Doomed Dimension", 1, 8},
  2498.     {"Realm of Black Magic", 9, 7},
  2499.     {"Netherworld", 16, 7},
  2500.     {"The Elder World", 23, 8},
  2501.     {"Final Level", 31, 1},
  2502.     {"Deathmatch Arena", 32, 6}
  2503. };
  2504.  
  2505. //MED 01/06/97  added hipnotic episodes
  2506. episode_t   hipnoticepisodes[] =
  2507. {
  2508.    {"Scourge of Armagon", 0, 1},
  2509.    {"Fortress of the Dead", 1, 5},
  2510.    {"Dominion of Darkness", 6, 6},
  2511.    {"The Rift", 12, 4},
  2512.    {"Final Level", 16, 1},
  2513.    {"Deathmatch Arena", 17, 1}
  2514. };
  2515.  
  2516. //PGM 01/07/97 added rogue episodes
  2517. //PGM 03/02/97 added dmatch episode
  2518. episode_t    rogueepisodes[] =
  2519. {
  2520.     {"Introduction", 0, 1},
  2521.     {"Hell's Fortress", 1, 7},
  2522.     {"Corridors of Time", 8, 8},
  2523.     {"Deathmatch Arena", 16, 1}
  2524. };
  2525.  
  2526. int    startepisode;
  2527. int    startlevel;
  2528. int maxplayers;
  2529. qboolean m_serverInfoMessage = false;
  2530. double m_serverInfoMessageTime;
  2531.  
  2532. void M_Menu_GameOptions_f (void)
  2533. {
  2534.     key_dest = key_menu;
  2535.     m_state = m_gameoptions;
  2536.     m_entersound = true;
  2537.     if (maxplayers == 0)
  2538.         maxplayers = svs.maxclients;
  2539.     if (maxplayers < 2)
  2540.         maxplayers = svs.maxclientslimit;
  2541. }
  2542.  
  2543.  
  2544. int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};
  2545. #define    NUM_GAMEOPTIONS    9
  2546. int        gameoptions_cursor;
  2547.  
  2548. void M_GameOptions_Draw (void)
  2549. {
  2550.     qpic_t    *p;
  2551.     int        x;
  2552.  
  2553.     M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") );
  2554.     p = Draw_CachePic ("gfx/p_multi.lmp");
  2555.     M_DrawPic ( (320-p->width)/2, 4, p);
  2556.  
  2557.     M_DrawTextBox (152, 32, 10, 1);
  2558.     M_Print (160, 40, "begin game");
  2559.  
  2560.     M_Print (0, 56, "      Max players");
  2561.     M_Print (160, 56, va("%i", maxplayers) );
  2562.  
  2563.     M_Print (0, 64, "        Game Type");
  2564.     if (coop.value)
  2565.         M_Print (160, 64, "Cooperative");
  2566.     else
  2567.         M_Print (160, 64, "Deathmatch");
  2568.  
  2569.     M_Print (0, 72, "        Teamplay");
  2570.     if (rogue)
  2571.     {
  2572.         char *msg;
  2573.  
  2574.         switch((int)teamplay.value)
  2575.         {
  2576.             case 1: msg = "No Friendly Fire"; break;
  2577.             case 2: msg = "Friendly Fire"; break;
  2578.             case 3: msg = "Tag"; break;
  2579.             case 4: msg = "Capture the Flag"; break;
  2580.             case 5: msg = "One Flag CTF"; break;
  2581.             case 6: msg = "Three Team CTF"; break;
  2582.             default: msg = "Off"; break;
  2583.         }
  2584.         M_Print (160, 72, msg);
  2585.     }
  2586.     else
  2587.     {
  2588.         char *msg;
  2589.  
  2590.         switch((int)teamplay.value)
  2591.         {
  2592.             case 1: msg = "No Friendly Fire"; break;
  2593.             case 2: msg = "Friendly Fire"; break;
  2594.             default: msg = "Off"; break;
  2595.         }
  2596.         M_Print (160, 72, msg);
  2597.     }
  2598.  
  2599.     M_Print (0, 80, "            Skill");
  2600.     if (skill.value == 0)
  2601.         M_Print (160, 80, "Easy difficulty");
  2602.     else if (skill.value == 1)
  2603.         M_Print (160, 80, "Normal difficulty");
  2604.     else if (skill.value == 2)
  2605.         M_Print (160, 80, "Hard difficulty");
  2606.     else
  2607.         M_Print (160, 80, "Nightmare difficulty");
  2608.  
  2609.     M_Print (0, 88, "       Frag Limit");
  2610.     if (fraglimit.value == 0)
  2611.         M_Print (160, 88, "none");
  2612.     else
  2613.         M_Print (160, 88, va("%i frags", (int)fraglimit.value));
  2614.  
  2615.     M_Print (0, 96, "       Time Limit");
  2616.     if (timelimit.value == 0)
  2617.         M_Print (160, 96, "none");
  2618.     else
  2619.         M_Print (160, 96, va("%i minutes", (int)timelimit.value));
  2620.  
  2621.     M_Print (0, 112, "         Episode");
  2622.    //MED 01/06/97 added hipnotic episodes
  2623.    if (hipnotic)
  2624.       M_Print (160, 112, hipnoticepisodes[startepisode].description);
  2625.    //PGM 01/07/97 added rogue episodes
  2626.    else if (rogue)
  2627.       M_Print (160, 112, rogueepisodes[startepisode].description);
  2628.    else
  2629.       M_Print (160, 112, episodes[startepisode].description);
  2630.  
  2631.     M_Print (0, 120, "           Level");
  2632.    //MED 01/06/97 added hipnotic episodes
  2633.    if (hipnotic)
  2634.    {
  2635.       M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);
  2636.       M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);
  2637.    }
  2638.    //PGM 01/07/97 added rogue episodes
  2639.    else if (rogue)
  2640.    {
  2641.       M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);
  2642.       M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);
  2643.    }
  2644.    else
  2645.    {
  2646.       M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);
  2647.       M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);
  2648.    }
  2649.  
  2650. // line cursor
  2651.     M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));
  2652.  
  2653.     if (m_serverInfoMessage)
  2654.     {
  2655.         if ((realtime - m_serverInfoMessageTime) < 5.0)
  2656.         {
  2657.             x = (320-26*8)/2;
  2658.             M_DrawTextBox (x, 138, 24, 4);
  2659.             x += 8;
  2660.             M_Print (x, 146, "  More than 4 players   ");
  2661.             M_Print (x, 154, " requires using command ");
  2662.             M_Print (x, 162, "line parameters; please ");
  2663.             M_Print (x, 170, "   see techinfo.txt.    ");
  2664.         }
  2665.         else
  2666.         {
  2667.             m_serverInfoMessage = false;
  2668.         }
  2669.     }
  2670. }
  2671.  
  2672.  
  2673. void M_NetStart_Change (int dir)
  2674. {
  2675.     int count;
  2676.  
  2677.     switch (gameoptions_cursor)
  2678.     {
  2679.     case 1:
  2680.         maxplayers += dir;
  2681.         if (maxplayers > svs.maxclientslimit)
  2682.         {
  2683.             maxplayers = svs.maxclientslimit;
  2684.             m_serverInfoMessage = true;
  2685.             m_serverInfoMessageTime = realtime;
  2686.         }
  2687.         if (maxplayers < 2)
  2688.             maxplayers = 2;
  2689.         break;
  2690.  
  2691.     case 2:
  2692.         Cvar_SetValue ("coop", coop.value ? 0 : 1);
  2693.         break;
  2694.  
  2695.     case 3:
  2696.         if (rogue)
  2697.             count = 6;
  2698.         else
  2699.             count = 2;
  2700.  
  2701.         Cvar_SetValue ("teamplay", teamplay.value + dir);
  2702.         if (teamplay.value > count)
  2703.             Cvar_SetValue ("teamplay", 0);
  2704.         else if (teamplay.value < 0)
  2705.             Cvar_SetValue ("teamplay", count);
  2706.         break;
  2707.  
  2708.     case 4:
  2709.         Cvar_SetValue ("skill", skill.value + dir);
  2710.         if (skill.value > 3)
  2711.             Cvar_SetValue ("skill", 0);
  2712.         if (skill.value < 0)
  2713.             Cvar_SetValue ("skill", 3);
  2714.         break;
  2715.  
  2716.     case 5:
  2717.         Cvar_SetValue ("fraglimit", fraglimit.value + dir*10);
  2718.         if (fraglimit.value > 100)
  2719.             Cvar_SetValue ("fraglimit", 0);
  2720.         if (fraglimit.value < 0)
  2721.             Cvar_SetValue ("fraglimit", 100);
  2722.         break;
  2723.  
  2724.     case 6:
  2725.         Cvar_SetValue ("timelimit", timelimit.value + dir*5);
  2726.         if (timelimit.value > 60)
  2727.             Cvar_SetValue ("timelimit", 0);
  2728.         if (timelimit.value < 0)
  2729.             Cvar_SetValue ("timelimit", 60);
  2730.         break;
  2731.  
  2732.     case 7:
  2733.         startepisode += dir;
  2734.     //MED 01/06/97 added hipnotic count
  2735.         if (hipnotic)
  2736.             count = 6;
  2737.     //PGM 01/07/97 added rogue count
  2738.     //PGM 03/02/97 added 1 for dmatch episode
  2739.         else if (rogue)
  2740.             count = 4;
  2741.         else if (registered.value)
  2742.             count = 7;
  2743.         else
  2744.             count = 2;
  2745.  
  2746.         if (startepisode < 0)
  2747.             startepisode = count - 1;
  2748.  
  2749.         if (startepisode >= count)
  2750.             startepisode = 0;
  2751.  
  2752.         startlevel = 0;
  2753.         break;
  2754.  
  2755.     case 8:
  2756.         startlevel += dir;
  2757.     //MED 01/06/97 added hipnotic episodes
  2758.         if (hipnotic)
  2759.             count = hipnoticepisodes[startepisode].levels;
  2760.     //PGM 01/06/97 added hipnotic episodes
  2761.         else if (rogue)
  2762.             count = rogueepisodes[startepisode].levels;
  2763.         else
  2764.             count = episodes[startepisode].levels;
  2765.  
  2766.         if (startlevel < 0)
  2767.             startlevel = count - 1;
  2768.  
  2769.         if (startlevel >= count)
  2770.             startlevel = 0;
  2771.         break;
  2772.     }
  2773. }
  2774.  
  2775. void M_GameOptions_Key (int key)
  2776. {
  2777.     switch (key)
  2778.     {
  2779.     case K_ESCAPE:
  2780.         M_Menu_Net_f ();
  2781.         break;
  2782.  
  2783.     case K_UPARROW:
  2784.         S_LocalSound ("misc/menu1.wav");
  2785.         gameoptions_cursor--;
  2786.         if (gameoptions_cursor < 0)
  2787.             gameoptions_cursor = NUM_GAMEOPTIONS-1;
  2788.         break;
  2789.  
  2790.     case K_DOWNARROW:
  2791.         S_LocalSound ("misc/menu1.wav");
  2792.         gameoptions_cursor++;
  2793.         if (gameoptions_cursor >= NUM_GAMEOPTIONS)
  2794.             gameoptions_cursor = 0;
  2795.         break;
  2796.  
  2797.     case K_LEFTARROW:
  2798.         if (gameoptions_cursor == 0)
  2799.             break;
  2800.         S_LocalSound ("misc/menu3.wav");
  2801.         M_NetStart_Change (-1);
  2802.         break;
  2803.  
  2804.     case K_RIGHTARROW:
  2805.         if (gameoptions_cursor == 0)
  2806.             break;
  2807.         S_LocalSound ("misc/menu3.wav");
  2808.         M_NetStart_Change (1);
  2809.         break;
  2810.  
  2811.     case K_ENTER:
  2812.         S_LocalSound ("misc/menu2.wav");
  2813.         if (gameoptions_cursor == 0)
  2814.         {
  2815.             if (sv.active)
  2816.                 Cbuf_AddText ("disconnect\n");
  2817.             Cbuf_AddText ("listen 0\n");    // so host_netport will be re-examined
  2818.             Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
  2819.             SCR_BeginLoadingPlaque ();
  2820.  
  2821.             if (hipnotic)
  2822.                 Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );
  2823.             else if (rogue)
  2824.                 Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );
  2825.             else
  2826.                 Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) );
  2827.  
  2828.             return;
  2829.         }
  2830.  
  2831.         M_NetStart_Change (1);
  2832.         break;
  2833.     }
  2834. }
  2835.  
  2836. //=============================================================================
  2837. /* SEARCH MENU */
  2838.  
  2839. qboolean    searchComplete = false;
  2840. double        searchCompleteTime;
  2841.  
  2842. void M_Menu_Search_f (void)
  2843. {
  2844.     key_dest = key_menu;
  2845.     m_state = m_search;
  2846.     m_entersound = false;
  2847.     slistSilent = true;
  2848.     slistLocal = false;
  2849.     searchComplete = false;
  2850.     NET_Slist_f();
  2851.  
  2852. }
  2853.  
  2854.  
  2855. void M_Search_Draw (void)
  2856. {
  2857.     qpic_t    *p;
  2858.     int x;
  2859.  
  2860.     p = Draw_CachePic ("gfx/p_multi.lmp");
  2861.     M_DrawPic ( (320-p->width)/2, 4, p);
  2862.     x = (320/2) - ((12*8)/2) + 4;
  2863.     M_DrawTextBox (x-8, 32, 12, 1);
  2864.     M_Print (x, 40, "Searching...");
  2865.  
  2866.     if(slistInProgress)
  2867.     {
  2868.         NET_Poll();
  2869.         return;
  2870.     }
  2871.  
  2872.     if (! searchComplete)
  2873.     {
  2874.         searchComplete = true;
  2875.         searchCompleteTime = realtime;
  2876.     }
  2877.  
  2878.     if (hostCacheCount)
  2879.     {
  2880.         M_Menu_ServerList_f ();
  2881.         return;
  2882.     }
  2883.  
  2884.     M_PrintWhite ((320/2) - ((22*8)/2), 64, "No Quake servers found");
  2885.     if ((realtime - searchCompleteTime) < 3.0)
  2886.         return;
  2887.  
  2888.     M_Menu_LanConfig_f ();
  2889. }
  2890.  
  2891.  
  2892. void M_Search_Key (int key)
  2893. {
  2894. }
  2895.  
  2896. //=============================================================================
  2897. /* SLIST MENU */
  2898.  
  2899. int        slist_cursor;
  2900. qboolean slist_sorted;
  2901.  
  2902. void M_Menu_ServerList_f (void)
  2903. {
  2904.     key_dest = key_menu;
  2905.     m_state = m_slist;
  2906.     m_entersound = true;
  2907.     slist_cursor = 0;
  2908.     m_return_onerror = false;
  2909.     m_return_reason[0] = 0;
  2910.     slist_sorted = false;
  2911. }
  2912.  
  2913.  
  2914. void M_ServerList_Draw (void)
  2915. {
  2916.     int        n;
  2917.     char    string [64];
  2918.     qpic_t    *p;
  2919.  
  2920.     if (!slist_sorted)
  2921.     {
  2922.         if (hostCacheCount > 1)
  2923.         {
  2924.             int    i,j;
  2925.             hostcache_t temp;
  2926.             for (i = 0; i < hostCacheCount; i++)
  2927.                 for (j = i+1; j < hostCacheCount; j++)
  2928.                     if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
  2929.                     {
  2930.                         Q_memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
  2931.                         Q_memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
  2932.                         Q_memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
  2933.                     }
  2934.         }
  2935.         slist_sorted = true;
  2936.     }
  2937.  
  2938.     p = Draw_CachePic ("gfx/p_multi.lmp");
  2939.     M_DrawPic ( (320-p->width)/2, 4, p);
  2940.     for (n = 0; n < hostCacheCount; n++)
  2941.     {
  2942.         if (hostcache[n].maxusers)
  2943.             sprintf(string, "%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
  2944.         else
  2945.             sprintf(string, "%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
  2946.         M_Print (16, 32 + 8*n, string);
  2947.     }
  2948.     M_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));
  2949.  
  2950.     if (*m_return_reason)
  2951.         M_PrintWhite (16, 148, m_return_reason);
  2952. }
  2953.  
  2954.  
  2955. void M_ServerList_Key (int k)
  2956. {
  2957.     switch (k)
  2958.     {
  2959.     case K_ESCAPE:
  2960.         M_Menu_LanConfig_f ();
  2961.         break;
  2962.  
  2963.     case K_SPACE:
  2964.         M_Menu_Search_f ();
  2965.         break;
  2966.  
  2967.     case K_UPARROW:
  2968.     case K_LEFTARROW:
  2969.         S_LocalSound ("misc/menu1.wav");
  2970.         slist_cursor--;
  2971.         if (slist_cursor < 0)
  2972.             slist_cursor = hostCacheCount - 1;
  2973.         break;
  2974.  
  2975.     case K_DOWNARROW:
  2976.     case K_RIGHTARROW:
  2977.         S_LocalSound ("misc/menu1.wav");
  2978.         slist_cursor++;
  2979.         if (slist_cursor >= hostCacheCount)
  2980.             slist_cursor = 0;
  2981.         break;
  2982.  
  2983.     case K_ENTER:
  2984.         S_LocalSound ("misc/menu2.wav");
  2985.         m_return_state = m_state;
  2986.         m_return_onerror = true;
  2987.         slist_sorted = false;
  2988.         key_dest = key_game;
  2989.         m_state = m_none;
  2990.         Cbuf_AddText ( va ("connect \"%s\"\n", hostcache[slist_cursor].cname) );
  2991.         break;
  2992.  
  2993.     default:
  2994.         break;
  2995.     }
  2996.  
  2997. }
  2998.  
  2999. //=============================================================================
  3000. /* Menu Subsystem */
  3001.  
  3002.  
  3003. void M_Init (void)
  3004. {
  3005.     Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
  3006.  
  3007.     Cmd_AddCommand ("menu_main", M_Menu_Main_f);
  3008.     Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
  3009.     Cmd_AddCommand ("menu_load", M_Menu_Load_f);
  3010.     Cmd_AddCommand ("menu_save", M_Menu_Save_f);
  3011.     Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f);
  3012.     Cmd_AddCommand ("menu_setup", M_Menu_Setup_f);
  3013.     Cmd_AddCommand ("menu_options", M_Menu_Options_f);
  3014.     Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
  3015.     Cmd_AddCommand ("menu_video", M_Menu_Video_f);
  3016.     Cmd_AddCommand ("help", M_Menu_Help_f);
  3017.     Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
  3018. }
  3019.  
  3020.  
  3021. void M_Draw (void)
  3022. {
  3023.     if (m_state == m_none || key_dest != key_menu)
  3024.         return;
  3025.  
  3026.     if (!m_recursiveDraw)
  3027.     {
  3028.         scr_copyeverything = 1;
  3029.  
  3030.         if (scr_con_current)
  3031.         {
  3032.             Draw_ConsoleBackground (vid.height);
  3033.             VID_UnlockBuffer ();
  3034.             S_ExtraUpdate ();
  3035.             VID_LockBuffer ();
  3036.         }
  3037.         else
  3038.             Draw_FadeScreen ();
  3039.  
  3040.         scr_fullupdate = 0;
  3041.     }
  3042.     else
  3043.     {
  3044.         m_recursiveDraw = false;
  3045.     }
  3046.  
  3047.     switch (m_state)
  3048.     {
  3049.     case m_none:
  3050.         break;
  3051.  
  3052.     case m_main:
  3053.         M_Main_Draw ();
  3054.         break;
  3055.  
  3056.     case m_singleplayer:
  3057.         M_SinglePlayer_Draw ();
  3058.         break;
  3059.  
  3060.     case m_load:
  3061.         M_Load_Draw ();
  3062.         break;
  3063.  
  3064.     case m_save:
  3065.         M_Save_Draw ();
  3066.         break;
  3067.  
  3068.     case m_multiplayer:
  3069.         M_MultiPlayer_Draw ();
  3070.         break;
  3071.  
  3072.     case m_setup:
  3073.         M_Setup_Draw ();
  3074.         break;
  3075.  
  3076.     case m_net:
  3077.         M_Net_Draw ();
  3078.         break;
  3079.  
  3080.     case m_options:
  3081.         M_Options_Draw ();
  3082.         break;
  3083.  
  3084.     case m_keys:
  3085.         M_Keys_Draw ();
  3086.         break;
  3087.  
  3088.     case m_video:
  3089.         M_Video_Draw ();
  3090.         break;
  3091.  
  3092.     case m_help:
  3093.         M_Help_Draw ();
  3094.         break;
  3095.  
  3096.     case m_quit:
  3097.         M_Quit_Draw ();
  3098.         break;
  3099.  
  3100.     case m_serialconfig:
  3101.         M_SerialConfig_Draw ();
  3102.         break;
  3103.  
  3104.     case m_modemconfig:
  3105.         M_ModemConfig_Draw ();
  3106.         break;
  3107.  
  3108.     case m_lanconfig:
  3109.         M_LanConfig_Draw ();
  3110.         break;
  3111.  
  3112.     case m_gameoptions:
  3113.         M_GameOptions_Draw ();
  3114.         break;
  3115.  
  3116.     case m_search:
  3117.         M_Search_Draw ();
  3118.         break;
  3119.  
  3120.     case m_slist:
  3121.         M_ServerList_Draw ();
  3122.         break;
  3123.     }
  3124.  
  3125.     if (m_entersound)
  3126.     {
  3127.         S_LocalSound ("misc/menu2.wav");
  3128.         m_entersound = false;
  3129.     }
  3130.  
  3131.     VID_UnlockBuffer ();
  3132.     S_ExtraUpdate ();
  3133.     VID_LockBuffer ();
  3134. }
  3135.  
  3136.  
  3137. void M_Keydown (int key)
  3138. {
  3139.     switch (m_state)
  3140.     {
  3141.     case m_none:
  3142.         return;
  3143.  
  3144.     case m_main:
  3145.         M_Main_Key (key);
  3146.         return;
  3147.  
  3148.     case m_singleplayer:
  3149.         M_SinglePlayer_Key (key);
  3150.         return;
  3151.  
  3152.     case m_load:
  3153.         M_Load_Key (key);
  3154.         return;
  3155.  
  3156.     case m_save:
  3157.         M_Save_Key (key);
  3158.         return;
  3159.  
  3160.     case m_multiplayer:
  3161.         M_MultiPlayer_Key (key);
  3162.         return;
  3163.  
  3164.     case m_setup:
  3165.         M_Setup_Key (key);
  3166.         return;
  3167.  
  3168.     case m_net:
  3169.         M_Net_Key (key);
  3170.         return;
  3171.  
  3172.     case m_options:
  3173.         M_Options_Key (key);
  3174.         return;
  3175.  
  3176.     case m_keys:
  3177.         M_Keys_Key (key);
  3178.         return;
  3179.  
  3180.     case m_video:
  3181.         M_Video_Key (key);
  3182.         return;
  3183.  
  3184.     case m_help:
  3185.         M_Help_Key (key);
  3186.         return;
  3187.  
  3188.     case m_quit:
  3189.         M_Quit_Key (key);
  3190.         return;
  3191.  
  3192.     case m_serialconfig:
  3193.         M_SerialConfig_Key (key);
  3194.         return;
  3195.  
  3196.     case m_modemconfig:
  3197.         M_ModemConfig_Key (key);
  3198.         return;
  3199.  
  3200.     case m_lanconfig:
  3201.         M_LanConfig_Key (key);
  3202.         return;
  3203.  
  3204.     case m_gameoptions:
  3205.         M_GameOptions_Key (key);
  3206.         return;
  3207.  
  3208.     case m_search:
  3209.         M_Search_Key (key);
  3210.         break;
  3211.  
  3212.     case m_slist:
  3213.         M_ServerList_Key (key);
  3214.         return;
  3215.     }
  3216. }
  3217.  
  3218.  
  3219. void M_ConfigureNetSubsystem(void)
  3220. {
  3221. // enable/disable net systems to match desired config
  3222.  
  3223.     Cbuf_AddText ("stopdemo\n");
  3224.     if (SerialConfig || DirectConfig)
  3225.     {
  3226.         Cbuf_AddText ("com1 enable\n");
  3227.     }
  3228.  
  3229.     if (IPXConfig || TCPIPConfig)
  3230.         net_hostport = lanConfig_port;
  3231. }
  3232.